Seebs said:
The code he gives using it is, in fact, consistently wrong. He does loops
of the form:
while (!feof(fp)) {
c = fgetc(fp);
fputc(c, fp2);
}
(simplified, but that's the essence).
Which is to say, loops which will in general try at least once to pass
EOF to fputc.
Consistently? I am not so sure. Listing 7 in chapter 9 seems to be
"fixed":
/* This code actually copies the file. */
while(!feof(in)) {
ch = getc(in);
if(!feof(in)) putc(ch, out);
}
Of course, not only is this not the idiomatic way to do IO in C, but
it fails to handle read errors. In another example (chapter 22 listing
16) the check on fread saves the day:
while(!feof(fp)) {
info = (struct address *) malloc(sizeof(struct address));
if(!info) {
printf("Out of Memory");
return;
}
if(1 != fread(info, sizeof(struct address), 1, fp)) break;
dls_store(info, &start, &last);
}
but the break causes a memory leak. In yet another (chapter 29
listing 9) a loop that looks wrong:
i = 0;
do {
*p = getc(fp);
p++; i++;
} while(!feof(fp) && i<PROG_SIZE);
is not quite as it seems because the string, p, is terminated by
overwriting EOF that gets read in. It still manages to fail on empty
input, though, because what follows is:
if(*(p-2) == 0x1a) *(p-2) = '\0'; /* null terminate the program */
else *(p-1) = '\0';
which has undefined behaviour when the input is empty.
In other words, there are lots of loops that are wrong but they don't
seem to be consistently wrong. Even the fact the feof testing often
misses read errors is not consistent as the example with fread shows.
There are simple cases of processing the EOF (chapter 9 listing 10 for
example) but the problems are not always that simple.
NOTE: I don't have this book so some of these may be explained in the
text: "don't do this" or "this has a problem that will be sorted out
later" although that does not seem likely.