In article <11************ **********@g14g 2000cwa.googleg roups.com>
googler <pi********@yah oo.com> wrote:
One more question. [The following code fragment, slightly edited for space]
while (!feof(fp)) {
fgets(str, 120, fp);
printf("%s", str);
}
... prints the last line twice. I don't understand why. When it prints
the last line for the first time, it should have known that the end of
the file has been reached,
What makes you believe that? Remember that fgets() is (loosely)
defined as:
int c;
while ((c = getc(fp)) != EOF && c != '\n') {
line[i++] = c;
if (c == '\n')
break;
}
line[i] = '\0';
(of course fgets() avoids overrunning your buffer, so it is a little
more complicated than that, but assume for the moment that no input
lines will be overlong).
Suppose the stdio "FILE *fp" is connected to a human being (at the
keyboard, or a terminal, or behind a network connection via telnet
or ssh or whatever), who has some way of signalling "end of file"
while still remaining connected (on many OSes this is done by
entering ^Z or ^D or @EOF or some similar character or string as
the only input on a line). The human types:
abc[enter]
so the first fgets() reads "abc\n". The fgets() call returns.
What should feof(fp) be?
The human *might* be *about* to press ^D or ^Z or type @EOF or
whatever it is that will signal EOF. Should feof(fp) wait until
he does so? What should it do if, instead, he types "def" and
presses ENTER?
You are effectively expecting the feof() predicate to predict the
future. There is no way for it to do that. It *could*, of course,
try to read input from the file -- in effect, waiting for the human
to signal EOF or enter "def\n". But it does not do that. Predicting
the future is too difficult. C is a simple language. It is much
easier to "predict" the past ... so that is what feof() does!
Instead of telling you "a future attempt to read is not going to
work because EOF is coming up", it tells you "a previous attempt
to read that failed, failed because EOF came up."
Suppose, now, that instead of a human, the stdio FILE *fp is
connected to a file on a floppy disk (or CD-ROM or DVD or whatever).
Suppose further that the floppy has been corrupted (someone used
a magnet to hold it up on the fridge, or scratched the CD-ROM, or
whatever). Your program/OS knows that the file should be 271483
bytes long, but partway in, the media turns out to be unreadable.
The fgetc() function -- or its getc() equivalent -- will return
EOF, indicating that it is unable to continue reading.
What should feof(fp) be? The file size is known (271483 bytes)
but you have at this point successfully read only 65536 bytes.
Should feof(fp) return nonzero (true)? You have not reached the
end of the file!
As before, feof() does not try to predict the future; instead, it
"predicts" the past. It tells you whether the getc() that returned
EOF did so because of end-of-file. In this case, it is *not* the
end of the file -- so feof(fp) is 0 (i.e., false). The other
predicate, ferror(fp), will be nonzero (i.e., true). It is
"predicting " the past, and telling you that the getc() failed due
to error. (Of course, the ability to distinguish between "normal
end of file" and "error reading data" is O/S and sometimes filesystem
or device specific, but it is fairly common.)
Because feof() only tells you about *previous* failures, and --
worse -- only tells you about EOF and not about errors, any loop
of the form:
while (!feof(fp))
is virtually *guaranteed* to be wrong. If you ever see this in
C code, be very suspicious.
As for why the last line prints twice, well, that one is a FAQ. :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.