10

I understand that fgets reads until EOF or a newline.

I wrote a sample code to read lines from a file and I observed that the fgets gets executed more than the desired number of times. It is a very simple file with exactly two blank lines, ie. I pressed enter once and saved the file.

Below is the code:

fp = fopen("sample.txt","r");
while (!feof(fp)) {
        fgets(line,150,fp);
        i++;
        printf("%s",line);
}
printf("%d",i);

Why is the while loop getting executed three times instead of 2, as there are only two blank lines in the file?

codeara
  • 111
  • 1
  • 2
  • 9
  • If you are on Linux, try to type `od -c sample.txt`. – Marian Jan 17 '14 at 07:41
  • I see four lines with this command...although only two lines are present in the file, i.e. only two \n are seen..@Marian – codeara Jan 17 '14 at 07:53
  • I found this [link](http://stackoverflow.com/questions/9434207/reading-from-file-using-fgets) that explains the same issue, but still I am not clear with the explanation. If fgets reads NULL the third time, why does it repeat the last line? Moreover, if it read the second line, the buffer should be cleared right? @Marian – codeara Jan 17 '14 at 07:54

1 Answers1

19

In your case, the last line is seemingly read twice, except that it isn't. The last call to fgets returns NULL to indicate the the end of file has been read. You don't check that, and print the old contents of the buffer again, because the buffer wasn't updated.

It is usually better not to use feof at all and check return values from the f... family of functions:

fp = fopen("sample.txt", "r");
while (1) {
        if (fgets(line,150, fp) == NULL) break;
        i++;
        printf("%3d: %s", i, line);
}
printf("%d\n",i);

The function feof returns true after trying to read beyond the end of the file, which only happens after your last (unsuccessful) call to fgets, which tries to read at or rather just before the end of the file. The answers in this long SO post explain more.

Community
  • 1
  • 1
M Oehm
  • 27,011
  • 3
  • 26
  • 39