2

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.

Community
  • 1
  • 1
Badda
  • 1,329
  • 2
  • 15
  • 40
  • 3
    Have you tried [`getline()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html)? – Andrew Henle May 04 '17 at 10:07
  • 1
    `if (res == theLineIWant)` doesn't do what you think it does - to compare strings you need to use `strcmp` – Chris Turner May 04 '17 at 10:09
  • If I am not wrong, getline() is either C++ either for Linux, so I can't use it ? As for comparing string with `==`I know it does not work, but I thought it would be more readable like that. Will edit – Badda May 04 '17 at 10:14
  • 2
    @Badda *If I am not wrong, getline() is either C++ either for Linux* `getline()` is POSIX-compliant C. Note where that link points to. – Andrew Henle May 04 '17 at 10:14

1 Answers1

2

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.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • I am trying to make getline() work on my code, so far it is not recognized by compiler. – Badda May 04 '17 at 12:40
  • @Badda Are you including the proper headers? And what compiler are you using? – Andrew Henle May 04 '17 at 13:43
  • I have included `stdlib`and `stdio`correctly. I am AtollicStudio IDE which uses GNU gcc ( I am not very familiar with these terms so I hope it is understable) – Badda May 04 '17 at 13:52
  • 1
    You need to add the proper feature test macros before including the headers in order to include for example POSIX features; "Since glibc 2.10: `_POSIX_C_SOURCE >= 200809L`". – Ilja Everilä May 05 '17 at 11:48
  • @IljaEverilä More precisely: "**If you're using glibc**, [y]ou need to add the proper feature test macros..." You probably should also add \@Badda (without the backslash - I had to add that so the comment system would allow that) to let Badda know. – Andrew Henle May 05 '17 at 11:59
  • 1
    I don't think it's just glibc specific. From ["2.2 The Compilation Environment"](http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_02): "A POSIX-conforming application shall ensure that the feature test macro _POSIX_C_SOURCE is defined before inclusion of any header." Please correct if I've misread/misunderstood something. – Ilja Everilä May 05 '17 at 14:29