pilkington pilkington - 12 days ago 8
C Question

Reading a line from text file dynamically

I am trying to learn how to dynamically allocate memory for very long lines when I'm reading a file. I search on here and web and I tried some code.

Firstly, here is my first non-dynamic code:

char line[256];
file = fopen(inputFileName, "r");
// Here, of course I checked file is opened or not.
while (fgets(line, sizeof(line), file)) {
// do some operations
}
// Closing operations


This works for me when I reading files. But here is line must be equal or less than 255 characters. So, I want to read for example 300 character length line from file.

I tried following code:

size_t maxl = 256;
//char line[256];
char *line = malloc(maxl * sizeof(char));
if(!line){
printf("Memory not allocated!!\n");
return -2;
}
file = fopen(inputFileName, "r");

while (fgets(line, sizeof(line), file)) {

while(line[strlen(line) - 1] != '\n' || line[strlen(line) - 1] != '\r'){
char *tmp = realloc (line, 2 * maxl);
//fgets(line, sizeof(line), file);
if (tmp) {
line = tmp;
maxl *= 2;
}
else{
printf("Not enough memory for this line!!\n");
return -3;
}
}
// do some operations
}


I tried to implement answers in this question actually: Reading a line from file in C, dynamically

But it always enter "Not enough memory" part of the code. So, what am I doing wrong?

Thank you already for your answers and advises.




Edit: Code is updated depend on first comments.




Edit 2: Code is always read same 3 characters from the file.

Imagine that the file is like:

abcdabcdabcd...


The
line
variable is always "abc" even after re-allocation operation.

Answer

Here are some corrections you need to do:

  • Change char *tmp = realloc (line, 2 * maxl); to char *tmp = realloc (line, 2 * maxl * sizeof(char); (just a suggestion!).
  • After reallocation of memory, you have to seek back in the file to read complete string. For instance, fseek(file,0,SEEK_SET); will seek to the beginning of the file inputFileName.
  • sizeof(line) will always be a constant value as you are computing the size of a character pointer, not the string length. So, change while (fgets(line, sizeof(line), file)) { to while (fgets(line, maxl, file)) {.
  • Move the commented line //fgets(line, sizeof(line), file); inside the if (tmp) block because you would want to read the string from file again after reallocation.
  • The expression line[strlen(line) - 1] != '\n' || line[strlen(line) - 1] != '\r' is logically incorrect. You may want to enter the loop only if the last character of the line is neither '\n' nor '\r'. So you must use a && there instead of ||.

Here is the modified code:

size_t maxl = 256;
//char line[256];
char *line = malloc(maxl * sizeof(char));
if(!line){
    printf("Memory not allocated!!\n");
    return -2;
}
file = fopen(inputFileName, "r");

while (fgets(line, maxl, file)) {

    while(line[strlen(line) - 1] != '\n' && line[strlen(line) - 1] != '\r'){
        char *tmp = realloc (line, 2 * maxl * sizeof(char));

        fseek(file,0,SEEK_SET);          //or wherever you want to seek to
        if (tmp) {
            line = tmp;
            maxl *= 2;
            fgets(line, maxl, file);
        }
        else{
            printf("Not enough memory for this line!!\n");
            return -3;
        }
    }
    printf("%s\n",line);     //just to check
}

The problems in your code were:

  • You were reading only a few characters from the file because you were reading sizeof(line) number of characters only and not maxl number of characters.
  • You may want to seek back some bytes to read the whole string again, but that is up to you.
  • Read a string again from the file after reallocation only if the reallocation is successful (if(tmp)).

Now, why that Not enough memory.. was printing?

It was because your loop was running multiple times and the reallocated memory size (maxl value) was increasing like 256, 512, 1024, 2048, ..., 65536, ...

When this size becomes large enough for the compiler to deny reallocation, you had that error string printed. If you like, try to debug your version of the code or print the value of maxl in each iteration of inner while loop.

Comments