How to modify ((c=getchar())!=NULL) to use fscanf or scanf instead?
For example, compact while loops are written like this in k&r
while ((c=getchar())!=NULL){
// do certain actions
}
and I want to convert a stanza like
fscanf ( FpSource, "%d" , &input );
while (input != EOF){
// do certain actions
fscanf ( FpSource, "%d" , &input );
}
into the above form with getchar() so that there is a single instance of fscanf.
More than one alternative would be appreciated.
Alternative #1,pretty much what you asked for:
while ( fscanf(FpSource, "%d", &input) , input != EOF ) {
The funny-looking thing inside the while() is an expression using
the comma operator -- yes, the comma can be an operator in C --
which evaluates its left-hand side (the fscanf() call), throws
the result away, then evaluates the right-hand side (input != EOF)
and yields the right-hand side's value as the value of the whole
expression.
I'd recommend against using this, though: There are too many
things that can go wrong. For starters, C promises that EOF is a
negative int, but doesn't specify any particular value. It is
very often -1, but could be something else (a case could be made
for -129 on some systems), so you don't really *know* what number
you should enter to stop the loop. Even if you do know the system's
EOF value (-1, say), what happens if you actually want to enter -1
as a legitimate datum? You're out of luck.
A worse problem occurs if fscanf() encounters "12.0" in the
input stream, or anything else that isn't strictly an int value.
On the first attempt it will digest "12", see that "." isn't a
digit and leave it alone, and store 12 in `input'. On the next
attempt it will see the "." again, realize that it can't make
any progress, and leave things unchanged: `input' will still be
12 from the first time. And you'll keep on getting 12 as the
value of `input' on the third, fourth, fifth, ... time until you
finally get tired and pull the plug on your program. Similar
trouble occurs if the input is "$42" or "(17)" or a myriad of
other non-numeric stuff.
Which leads us to Alternative #2, not what you asked for but
perhaps closer to what you should have asked for:
while (fscanf(FpSource, "%d", &input) == 1) {
In this alternative you're not making the continue/stop decision
based on the value of the number from the input, but on whether
fscanf() was able to find a number at all. fscanf() returns the
number of items it successfully read and stored; you're asking
for one item, so fscanf() returns 1 if and only if it was actually
able to make integer sense of its input. In the "12.0" example
above, the first call would convert "12" to 12, store it in `input',
and return 1. The second call would stall on the ".", leave `input'
unchanged, and return 0 -- and your program would then know that
you'd either reached the end of the input stream or encountered
something undigestible in it.
You might be interested in telling those two cases apart,
which leads to Alternative #3:
int status;
...
while ((status = fscanf(FpSource, "%d", &input)) == 1) {
...
}
if (status == EOF) {
... read all the way to the end ...
} else {
... found garbage somewhere in mid-stream ...
}
I might use #3 in a quick one-off program or if I had good
reason to believe the input was well-structured (e.g., the input
was the unedited output of some other program known to be well-
behaved). For input from a less well-controlled source -- in
particular, for interactive input -- even #3 isn't robust enough
for real-world use. I'll refer you to Question 12.20 and its
various links and footnotes on the comp.lang.c Frequently Asked
Questions (FAQ) page at <
http://www.c-faq.com/> for an exposition
of some of the issues and some hints about coping with them.