gfcf14 gfcf14 - 4 months ago 19
C Question

Character pointers pointing to character array instead of assigning

I'm preparing a program to read a file:

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

#define MAXLEN 256

int main(int argc, char** argv) {

FILE *fp;
char currLine[MAXLEN];

char **fileLines = malloc(MAXLEN * sizeof(char *));
for (int i = 0; i < MAXLEN; i++) {
fileLines[i] = malloc(MAXLEN * sizeof(char));
}

int lineCounter = 0;

fp = fopen("sample.txt", "r");

while (fgets(currLine, sizeof(currLine), fp)) {
fileLines[lineCounter] = currLine;
printf("%s", fileLines[lineCounter]);
lineCounter++;
}

printf("\n\n");

for (int i = 0; i < lineCounter; i++) {
printf("%s\n", fileLines[i]);
}

/*for (int i = 0; i < MAXLEN; i++) {
free(fileLines[i]);
}*/
free(fileLines);

fclose(fp);
return 0;
}


Within the while loop, I read a line of file from the text file
sample.txt
:

first line
2nd
linea tres
#4


And attempt to assign the character array to one of the character pointers from the double pointer, then print. At that moment, printing happens correctly, but once outside of the loop, I print each item again, and they all print the last element:

OUTPUT:

first line
2nd
linea tres
#4

#4
#4
#4
#4


From this, my suspicion is that what the "assignment" is actually doing is pointing towards the local variable
currline
, whose last value is
#4
. So how could I correctly assign the line read instead of pointing to the character array? Thanks for any help in advice

Answer

In the loop where you read the file, you must strip the trailing linefeed and copy the contents of each line read into the array. You currently store a pointer to the line buffer for each line read. All lines in the string array point to the same buffer, which at best holds the last line read from the file.

Here is an improved version of this loop:

while (lineCounter < MAXLEN && fgets(currLine, sizeof(currLine), fp)) {
    currLine[strcspn(currLine, "\n")] = '\0';
    strcpy(fileLines[lineCounter], currLine);
    printf("%s\n", fileLines[lineCounter]);  // debug
    lineCounter++;
}

This mistake also explains why you could nor free the lines in the fileLines array. These pointers no longer pointed to allocated space, invoking undefined behavior when passed to free().

Note that instead of pre-allocating a full array of lines, you could allocate the exact space for each line read from the file this way:

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

#define MAXLEN 256

int main(int argc, char** argv) {

    char currLine[MAXLEN];
    char **fileLines = malloc(MAXLEN * sizeof(char *));
    for (int i = 0; i < MAXLEN; i++) {
        fileLines[i] = NULL;
    }

    int lineCounter = 0;

    FILE *fp = fopen("sample.txt", "r");
    if (fp == NULL)
        return 1;

    while (lineCounter < MAXLEN && fgets(currLine, sizeof(currLine), fp)) {
        currLine[strcspn(currLine, "\n")] = '\0';
        fileLines[lineCounter] = strdup(currLine);
        lineCounter++;
    }
    fclose(fp);

    for (int i = 0; i < lineCounter; i++) {
        printf("%s\n", fileLines[i]);
    }

    for (int i = 0; i < lineCounter; i++) {
        free(fileLines[i]);
    }
    free(fileLines);

    return 0;
}
Comments