views:

386

answers:

5

Probably an extremely simple answer to this extremely simple question:

I'm reading "C Primer Plus" by Pratta and he keeps using the example

while (scanf("%d", &num) == 1)...

Is the == 1 really necessary? It seems like one could just write:

while (scanf("%d", &num))

It seems like the equality test is unnecessary since scanf returns the number of objects read and 1 would make the while loop true. Is the reason to make sure that the number of elements read is exactly 1 or is this totally superfluous?

Thanks in advance.

+3  A: 

You understood the C code correctly.

Sometimes the reason for testing the number of items read is that someone wants to make sure that all items were read instead of scanf quitting early when it the input didn't match the expected type. In this particular case it didn't matter.

Usually scanf is a poor choice of functions because it doesn't meet the needs of interactive input from a human user. Usually a combination of fgets and sscanf yield better results. In this particular case it didn't matter.

If later chapters explain why some kinds of coding practices are better than this trivial example, good. But if not, you should dump the book you're reading.

On the other hand, your substitute code isn't exactly a substitute. If scanf returns -1 then your while loop will execute.

Windows programmer
Wrong, see the other answers. It returns -1 when EOF is hit or a read error occurs.
Adam Rosenfield
"Wrong, see the other answers." -- you mean wrong, see my own answer, because that's why I wrote "If scanf returns -1 then your while loop will execute."
Windows programmer
+3  A: 

Since scanf returns the value EOF (which is -1) on end of file, the loop as written is correct. It runs as long as the input contains text that matches %d, and stops either at the first non-match or end of file.

It would have been clearer at a glance if scanf were expecting more than one input....

while (scanf("%d %d", &x, &y)==2) { ... }

would exit the loop when the first time it was unable to match two values, either due to end of file end of file (scanf returns EOF (which is -1)) or on input matching error (e.g. the input xyzzy 42 does not match %d %d so scanf stops on the first failure and returns 0 without writing to either x or y) when it returns some value less than 2.

Of course, scanf is not your friend when parsing real input from normal humans. There are many pitfalls in its handling of error cases.

Edit: Corrected an error: scanf returns EOF on end of file, or a non-negative integer counting the number of variables it successfully set.

The key point is that since any non-zero value is TRUE in C, failing to test the return value correctly in a loop like this can easily lead to unexpected behavior. In particular, while(scanf(...)) is an infinite loop unless it encounters input text that cannot be converted according to its format.

And I cannot emphasize strongly enough that scanf is not your friend. A combination of fgets and sscanf might be enough for some simple parsing, but even then it is easily overwhelmed by edge cases and errors.

RBerteig
+1  A: 

While you are correct it is not strictly necessary, some people prefer it for several reasons.

First, by comparing to 1 it becomes an explicit boolean value (true or false). Without the comparison, you are testing on an integer, which is valid in C, but not in later languages (like C#).

Secondly, some people would read the second version in terms of while([function]), instead of while([return value]), and be momentarily confused by testing a function, when what is clearly meant is testing the return value.

This can be completely a matter of personal preference, and as far as I'm concerned, both are valid.

abelenky
+5  A: 

In C, 0 is evaluated to false and everything else to true. Thus, if scanf returned EOF, which is a negative value, the loop would evaluate to true, which is not what you'd want.

JRL
A: 

One probably could write it without an explicit comparison (see the JRL's answer though), but why would one? I'd say that comparison-less conditions should only be used with values that have explicitly boolean semantics (like an isdigit() call, for example). Everything else should use an explicit comparison. In this case (the result of scanf) the semantics is pronouncedly non-boolean, so the explicit comparison is in order.

Also, the comparison one can usually omit is normally a comparison with zero. When you feel the urge to omit the comparison with something else (like 1 in this case) it is better to think twice and make sure you know what your are doing (see the JRL's answer again).

In any case, when the comparison can be safely omitted and you actually omit it, the actual semantical meaning of the condition remains the same. It has absolutely no impact on the efficiency of the resultant code, if that's something you are worrying about.

AndreyT