0

I have a file with an unknown number of strings and each of these strings is of an unknown length. I would like to make each line of the file its own string in an array of strings.

I tried to use dynamic allocation in a char** array, but I don't think I'm approaching this correctly.

Below is the code I have tried. It's getting stuck in an infinite loop, and I can't figure out why. (The text file I'm reading from ends with a line break, by the way.)

#include <getopt.h> //for getopts 
#include <sys/stat.h> //to do file stat
#include <dirent.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h> //user macros
#include <stdlib.h>
#include <stdbool.h>
#include <libgen.h>
#include <errno.h>

int main(int argc, char *argv[]) {
    //storing the filename inside string
    char* filename = argv[1];


    FILE *fp1 = fopen(filename, "r");
    if (fp1 == NULL) {
        fprintf(stderr, "Error: Cannot open '%s'. No such file or directory.\n", filename);
        return EXIT_FAILURE;
    }
    
    /**
     * we begin by getting the number of numbers in the file
     * the number of numbers = number of lines = number of line breaks
     */
    size_t numNumbers = 0;

    // while((fscanf(fp1, "%*[^\n]"), fscanf(fp1, "%*c")) != EOF){
    //     numNumbers = numNumbers + 1;
    // }
    char c;
    while((c = fgetc(fp1)) != EOF){
        if(c == '\n'){
            numNumbers++;
        }
    }

    fclose(fp1); 

    FILE *fp2 = fopen(filename, "r");
    char** arrayOfStrings = malloc(numNumbers * sizeof(char*));

    for(int i = 0; i < numNumbers; i++) {
        int len = 0;
        if(((c = fgetc(fp1)) != '\n') && (c != EOF)){
            len++;
        }
        arrayOfStrings[i] = malloc(len * sizeof(char));
    }

    printf("hello1\n");

    //for(int i = 0; i < numNumbers; i++){
    //    fscanf(fp2, "%s", (arrayOfStrings[i]));
    //}

    fclose(fp2);

    // for(int i = 0; i < numNumbers; i++){
    //     fprintf(stdout, "%s", arrayOfStrings[i]);
    // }
    return 0;
}

(I'm very new to C, so please go easy on me!)

  • See the linked missing null terminator FAQ. Scroll down in the answer to the part "When allocating memory for a string dynamically in run-time, you also need to allocate room for the null terminator" – Lundin Mar 04 '22 at 09:11

2 Answers2

0

In C, strings are terminated with a '0' byte, so it looks like your malloc for each string is 1 character too short -- you've only allowed space for the text.

In addition, you mean the count for the size of each line to be a while loop, not an if statement - right now you are counting each line as length "1".

Finally, you are reading off the end of the file in your commented out fscanf code because you haven't closed and reopened it.

Alex Nicolaou
  • 217
  • 1
  • 4
0

Assuming you want to split the input to the strings by the newline character, would you please try:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *filename;                     // filename to read
    char **arrayOfStrings = NULL;       // array of strings
    char line[BUFSIZ];                  // line buffer while reading
    char *p;                            // temporal pointer to the input line
    int i, num;                         // counter for lines
    FILE *fp;                           // file pointer to read

    if (argc != 2) {
        fprintf(stderr, "usage: %s file.txt\n", argv[0]);
        return EXIT_FAILURE;
    }
    filename = argv[1];
    if (NULL == (fp = fopen(filename, "r"))) {
        perror(filename);
        return EXIT_FAILURE;
    }
    // read the input file line by line
    while (fgets(line, BUFSIZ, fp)) {
        if ((p = strrchr(line, '\n'))) *p = '\0';       // remove trailing newline, if any
        if ((p = strrchr(line, '\r'))) *p = '\0';       // remove trailing cr character, if any

        if (NULL == (arrayOfStrings = realloc(arrayOfStrings, (num + 1) * sizeof(char **)))) {
                                                        // enlarge the array according to the line count
            perror("realloc");
            return EXIT_FAILURE;
        }
        if (NULL == (arrayOfStrings[num] = malloc(strlen(line) + 1))) {
                                                        // memory for the string of the line
            perror("malloc");
            return EXIT_FAILURE;
        }
        strcpy(arrayOfStrings[num], line);
        num++;
    }

    // print the strings in the array
    for (i = 0; i < num; i++) {
        printf("%d %s\n", i, arrayOfStrings[i]);
    }

    fclose(fp);
    return 0;
}

If the input file looks something like:

This
is
the
input.

Then the output will be:

0 This
1 is
2 the
3 input.
tshiono
  • 21,248
  • 2
  • 14
  • 22