Badda
Badda

Reputation: 1369

Handle memory while reading long lines from a file in C

First of all, I know this question is very close to this topic, but the question was so poorly worded that I am not even sure it is a duplicate plus no code were shown so I thought it deserved to be asked properly.

I am trying to read a file line by line and I need to store a line in particular in a variable. I have managed to do so quite easily using fgets, nevertheless the size of the lines to be read and the number of lines in the file remain unknown.
I need a way to properly allocate memory to the variable whatever the size of the line might be, using C and not C++.

So far my code looks like that :

allowedMemory = malloc(sizeof(char[1501])); // Checks if enough memory
if (NULL == allowedMemory)
{
    fprintf(stderr, "Not enough memory. \n");
    exit(1);
}
else
    char* res;
    res = allowedMemory;
while(fgets(res, 1500, file)) // Iterate until end of file
{
    if (res == theLineIWant) // Using strcmp instead of ==
        return res;
}

The problem of this code is that it is not adaptable at all. I am looking for a way to allocate just enough memory to res so that I don't miss any data in line.

I was thinking about something like that :

while ( lineContainingKChar != LineContainingK+1Char) // meaning that the line has not been fully read
// And using strcmp instead of ==
  realloc(lineContainingKChar, K + 100) // Adding memory

But I would need to iterate through two FILE object in order to fill these variables which would not be very efficient. Any hints about how to implement this solution or advise about how to do it in a easier way would be appreciated.

EDIT : Seems like using getline() is the best way to do so because this function allocates the memory needed by itself and free it when needed. Nevertheless I don't think that it is 100% portable since I still can't use it though I have included <stdio.h>. To be verified though, since my issues are often situated between keyboard and computer. Until then I am still open to a solution which would not use POSIX-compliant C.

Upvotes: 2

Views: 506

Answers (1)

Andrew Henle
Andrew Henle

Reputation: 1

getline() appears to do exactly what you want:

DESCRIPTION

The getdelim() function shall read from stream until it encounters a character matching the delimiter character.

...

The getline() function shall be equivalent to the getdelim() function with the delimiter character equal to the <newline> character.

...

EXAMPLES

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


int main(void)
{
    FILE *fp;
    char *line = NULL;
    size_t len = 0;
    ssize_t read;
    fp = fopen("/etc/motd", "r");
    if (fp == NULL)
        exit(1);
    while ((read = getline(&line, &len, fp)) != -1) {
        printf("Retrieved line of length %zu :\n", read);
        printf("%s", line);
    }
    if (ferror(fp)) {
        /* handle error */
    }
    free(line);
    fclose(fp);
    return 0;
}

And per the Linux man page:

DESCRIPTION

getline() reads an entire line from stream, storing the address of the buffer containing the text into *lineptr. The buffer is null- terminated and includes the newline character, if one was found.

If *lineptr is set to NULL and *n is set 0 before the call, then getline() will allocate a buffer for storing the line. This buffer should be freed by the user program even if getline() failed.

Alternatively, before calling getline(), *lineptr can contain a pointer to a malloc(3)-allocated buffer *n bytes in size. If the buffer is not large enough to hold the line, getline() resizes it with realloc(3), updating *lineptr and *n as necessary.

In either case, on a successful call, *lineptr and *n will be updated to reflect the buffer address and allocated size respectively.

Upvotes: 2

Related Questions