10

what is the correct way to read a text file until EOF using fgets in C? Now I have this (simplified):

char line[100 + 1];
while (fgets(line, sizeof(line), tsin) != NULL) { // tsin is FILE* input
   ... //doing stuff with line
}

Specifically I'm wondering if there should be something else as the while-condition? Does the parsing from the text-file to "line" have to be carried out in the while-condition?

Johan
  • 863
  • 3
  • 13
  • 28
  • The parsing should be done in the while loop or I guess you could store each line into an array or something and then do your parsing after the while loop. Close the file when you're done with it too – FreeStyle4 Aug 16 '16 at 13:46
  • That's 100% OK, you could even just do `while (fgets(line, sizeof(line), tsin)) {...}` and let the return of `fgets` serve as the test in and of itself. (a valid pointer will test `true` and `NULL` will test `false`) – David C. Rankin Aug 16 '16 at 14:15
  • I think you are doing right, the answer about leaving out != NULL does not add value. – AndersK Aug 16 '16 at 20:00

3 Answers3

9

According to the reference

On success, the function returns str. If the end-of-file is encountered while attempting to read a character, the eof indicator is set (feof). If this happens before any characters could be read, the pointer returned is a null pointer (and the contents of str remain unchanged). If a read error occurs, the error indicator (ferror) is set and a null pointer is also returned (but the contents pointed by str may have changed).

So checking the returned value whether it is NULL is enough. Also the parsing goes into the while-body.

bigahega
  • 405
  • 2
  • 6
3

What you have done is 100% OK, but you can also simply rely on the return of fgets as the test itself, e.g.

char line[100 + 1] = "";  /* initialize all to 0 ('\0') */

while (fgets(line, sizeof(line), tsin)) { /* tsin is FILE* input */
    /* ... doing stuff with line */
}

Why? fgets will return a pointer to line on success, or NULL on failure (for whatever reason). A valid pointer will test true and, of course, NULL will test false.

(note: you must insure that line is a character array declared in scope to use sizeof line as the length. If line is simply a pointer to an array, then you are only reading sizeof (char *) characters)

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • I see little value to initialize all `line[]` other than style/debug. Do you see other value? – chux - Reinstate Monica Aug 16 '16 at 15:35
  • Nope, other than always trying to impress upon new C programmers that the cost of initializing all variables is quite small compared to the time spent debugging when you don't. In this case, that's the only point. – David C. Rankin Aug 16 '16 at 15:38
  • your code implies that NULL is 0, but that is not the case on all platforms. – AndersK Aug 16 '16 at 20:01
  • @AndersK., That's true according to the C standard, but [Posix](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stddef.h.html) is stricter. – James K. Lowden Aug 16 '16 at 22:10
  • @AndersK. do you have an example of a platform where `while (fgets(...))` would fail? I'm curious, I haven't run across one. – David C. Rankin Aug 16 '16 at 22:13
  • @DavidC.Rankin see e.g. http://stackoverflow.com/questions/2597142/when-was-the-null-macro-not-0 but true, maybe it is irrelevant nowadays (I'm old) – AndersK Aug 17 '16 at 07:17
  • Considering I've got 2 in high school and 1 in middle-school and I've been around since the mid 60's, you can't be that much older... – David C. Rankin Aug 17 '16 at 17:14
0


i had the same problem and i solved it in this way

while (fgets(line, sizeof(line), tsin) != 0) { //get an int value
   ... //doing stuff with line
}