2

I'm a beginner of C. When I use this while loop to print the contains of a file. The last line will print twice on Linux. It should not get into while loop when reach the end of file. It has no problem on windows.

#include <stdio.h>
#include <unistd.h>

int main()
{

    char string[400];
    FILE *file_para;

    // Open the file
    if ((file_para = fopen("Test.txt", "r")) == NULL)
    {
        printf("cannot open file\n");
        getchar();
        return 0;
    }

    while (!feof(file_para))
    {
        fgets(string, 400, file_para);
        printf("**** %s", string);
    }

    fclose(file_para);
    getchar();
    return 0;
}
lurker
  • 56,987
  • 9
  • 69
  • 103
Dan
  • 339
  • 1
  • 3
  • 6
  • 1
    Use `fgets(...)` as your loop condition. It will return `NULL` when it fails to read more characters. – user123 Sep 17 '13 at 00:37
  • 2
    The problem with the `feof` check (or at least the thing to be aware of) is that it is documented: "This indicator is generally set by a previous operation on the stream that attempted to read at or past the end-of-file." So you may be right at the end of file and it will still not indicate EOF until you do another read. So the last `fgets` that you've done may be past end of file. As @MohammadAliBaydoun indicates, you should use your `fgets` call as your read and your EOF check for the loop. – lurker Sep 17 '13 at 00:42

2 Answers2

1

This is a common anti-pattern:

while (!feof(file_para))
{
    fgets(string, 400, file_para);

feof() does not detect if the next input call will fail due to end-of-file; it tells you if the file has already reached end-of-file. You should only call it after an input function has already failed, to see why it failed (which could be either an error or end-of-file).

The correct pattern is:

while (fgets(string, 400, file_para))
{
caf
  • 233,326
  • 40
  • 323
  • 462
1

This is the wrong way to use feof(). Use feof() to detect what went wrong after one of the main I/O functions failed. It does not predict whether you're about to reach EOF; it tells you when some I/O function has already reported EOF. C is not Pascal; in Pascal, you can (must?) check for EOF before calling the I/O functions.

while (fgets(string, sizeof(string), file_para) != 0)
{
    ...do printing, etc...
}
// If you need to, use `feof()` and `ferror()` to sort out what went wrong.

If you really, really insist on using feof(), then you also need to check your I/O operation:

while (!feof(file_para))
{
    if (fgets(string, sizeof(string), file_para) == 0)
        break;
    ...do printing, etc...
}

Note that you might be failing because ferror(file_para) evaluates to true even when feof(file_para) does not...so maybe you need while (!feof(file_para) && !ferror(file_para)), but that really is just more evidence that the while loop should be conditioned on the I/O function, not feof().

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278