-1

I want to read from a file and create a dynamic array based on it (for using the qsort()) method on. I've got the following code to get the number of lines in the file (that meet a certain criteria, but don't know how to populate the individual elements of the array).

FILE* file = fopen("$filename", "r");
int count = 0; // Count num lines in the file
char buffer[50];
while(fgets(buffer, 50, file)) {
    count++;
}

char** myArray;
myArray = malloc(count * sizeof(char*));
for (int i = 0; i < count; i++) {
    myArray[i] = malloc(sizeof(char) * 51); // to include space for terminating character
}

// Re-open the file
fclose(file);
fopen("$filename", "r");

int ctr = 0; // Indexing for the array.

while(fgets(buffer, 50, file)) {
    char* word = malloc(sizeof(char) * (strlen(buffer) + 1));
    strcpy(myArray[ctr], word);
    ctr++;
    free(word);
}

for (int i = 0; i < count; i++) {
    printf("%s\n", myArray[ctr]); // This just prints 7 new lines.
}
dreamcrash
  • 47,137
  • 25
  • 94
  • 117
flying_loaf_3
  • 397
  • 2
  • 3
  • 12
  • Just as a side note: Instead of closing and reopening the file, it would be simpler to call `fseek( file, 0, SEEK_SET );` to jump back to the start of the file. – Andreas Wenzel Mar 16 '21 at 23:54
  • Before sorting, you probably want to remove the newline character that was read in by `fgets`. See the following question for the best way to do this: [Removing trailing newline character from fgets() input](https://stackoverflow.com/q/2693776/12149471) – Andreas Wenzel Mar 16 '21 at 23:56
  • Do you want each entry of the array to be what? A character of the text file or a line? – lnogueir Mar 16 '21 at 23:56
  • @AndreasWenzel have done that in my implementation, but thought that wasn't relevant to the 'minimal reproducible example' that is often the convention on here. Thanks for the tip on fseek tho – flying_loaf_3 Mar 16 '21 at 23:58
  • Uses `ctr` uninitialized so the whole thing has undefined behavior. Memory leak of `word`. Copy uninitialized memory into `myArray` (strcpy is (dest, src)) – John3136 Mar 16 '21 at 23:59
  • @Inogueir I want it to be a word, like "apple" – flying_loaf_3 Mar 16 '21 at 23:59
  • Btw, there are errors in this code such as an extra ```)``` at the end of ```char* word``` line, and on the last print statement, you are doing ```myArray[ctr]``` which will be a segmentation fault. Not sure if you have that on your original code, but please update the code in your question to output what you said it outputs. – lnogueir Mar 17 '21 at 00:02
  • @Inogueir thanks for that! Didn't even notice. Fixed the first mistake. How would I access the 'ctr'th element without segfaulting then? – flying_loaf_3 Mar 17 '21 at 00:06
  • Tip: Don't split your declarations from your definitions. Prefer `char* x = malloc(...)` vs. `char*x; x = malloc(...)` – tadman Mar 17 '21 at 00:07
  • @tadman that make sense. Does anyone know how I would set the elements of the array correctly though? – flying_loaf_3 Mar 17 '21 at 00:10
  • I'd steer towards using an array of default `NULL`, then use `strcpy()` to populate it, allocating *exactly* the right size, not a wild guess like `50` that is probably wrong. – tadman Mar 17 '21 at 00:12
  • @tadman that was done because I know that the max line length of the file will be 45 chars. – flying_loaf_3 Mar 17 '21 at 00:13
  • That's an *assumption*, which is usually where mistakes happen. – tadman Mar 17 '21 at 00:16

1 Answers1

1

You can simplify the code:

  • no need to allocate all lines in the array of pointers, just allocate the lines as you read the file.
  • no need to close and reopen the file, just rewind() the stream.

Here is a modified version:

char **read_file(const char *filename, int *countp) {
    FILE *file = fopen(filename, "r");
    int count = 0; // Count num lines in the file
    char buffer[200];

    while (fgets(buffer, sizeof buffer, file)) {
        count++;
    }
    
    char **myArray = malloc(count * sizeof(char *));
    if (myArray == NULL) {
        fclose(file);
        return NULL;
    }
    
    rewind(file);
    
    int ctr = 0; // Indexing for the array.
    
    while (ctr < count && fgets(buffer, sizeof, file)) {
        // you might want to strip the trailing newline
        //buffer[strcspn(buffer, "\n")] = '\0';
        myArray[ctr++] = strdup(buffer);
    }
    fclose(file);
    
    for (int i = 0; i < ctr; i++) {
        printf("%s", myArray[i]);
    }
    *countp = count;
    return myArray;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189