beardeadclown
beardeadclown

Reputation: 377

Check EOF after fread in a loop

I figured out why the following loop was giving me bad input, re Why is “while ( !feof (file) )” always wrong?

do {
    if (fread(buf, 1, siz, stdin) != siz) {
        if (feof(stdin))
            fputs("bad input\n", stderr);
        else /* implying ferror(stdin) */
            perror("fread() failed");
        return EXIT_FAILURE;
    }
    use(buf);
} while (!feof(stdin));

Is it inevitable to write some auxiliary function/weird call for properly(?) checking EOF along the lines of ungetc(getchar(), stdin) or is there a better way?

Upvotes: 0

Views: 444

Answers (2)

Andreas Wenzel
Andreas Wenzel

Reputation: 25396

There is no need to use ungetc to check for end-of-file. Instead, you can rewrite your loop to the following:

while ( fread(buf, 1, siz, stdin) == siz )
{
    use(buf);
}

//verify that the loop was terminated due to end-of-file and not due
//to stream error
if ( ferror(stdin) )
{
    perror( "fread() failed" );
    return EXIT_FAILURE;
}

//No stream error occurred, so the loop must have been terminated due
//to end-of-file. Therefore, everything is ok and we can continue
//running the program normally.

Depending on the situation, you may want to additionally check whether a partial read occurred, and also treat that as an error. See the other answer on how you can do that.

Upvotes: 0

Ture Pålsson
Ture Pålsson

Reputation: 6806

I'd do something like

size_t nread;
while ((nread = fread(buf, 1, siz, stdin)) == siz) {
    use(buf);
}

if (feof(stdin)) {
    if (nread == 0) {
        /* Normal EOF; do nothing. I would not actually
           write this branch. :-) */
    } else {
        /* Short read. */
        fputs("bad data\n", stderr); }
    }
} else {
    perror("fread");
} 

Upvotes: 2

Related Questions