scanf(..)

Steve Summit scs at adam.pika.mit.edu
Mon Jun 5 04:20:58 AEST 1989


In article <225800176 at uxe.cso.uiuc.edu> burkie at uxe.cso.uiuc.edu
manages to ask about nearly all of scanf's crippling problems.

The short (unhelpful, but adamantly-held-by-me) answer is "don't
use scanf."  Unfortunately, it's nearly impossible not to use
scanf, because it's so damn convenient, and all the C books teach
you about it early, because it's the apparently easiest way of
having little toy programs ask the user questions.

>char	c;
>scanf("%c", &c);
>
>I find that sometimes the program above doesn't stop
>at the scanf to wait for input, esp. if there are other
>input, print etc. statements.. Do I have to flush some 
>buffers etc for this to work properly?

If you are trying to wait for the user to hit a key, this is not
the way to do it.  scanf is both buffered and, typically, line
based.  Not only are all characters the user types saved until
explicitly read (even if by a later scanf which you had wanted to
wait for new input) but scanf normally can't even start processing
input until the user has pressed the return key, so scanf("%c")
won't necessarily give you character-at-a-time input.  (Whether
input is character-at-a-time or "line buffered" is actually not
a function of scanf at all, but of the operating system and/or
device driver which is supplying scanf with characters.)

If you're using MS-DOS, a function usually called kbhit() will
tell you whether the user has hit a key or not.  (One of the two
nice things I can say about DOS is that it makes this common
operation easy.)  If you're not using DOS, try to figure out a
way not to need to do this or, barring that, read comp.lang.c
and/or comp.unix.wizards, where the question has just been asked
for the 47th time this month.  (The answer depends entirely on
what system you're using.)

Flushing the input buffer, though occasionally important, is
likewise system-dependent.  (fflush on stdin works on some
systems, but is nonportable and does nothing about characters
read by the operating system but not yet delivered to the stdio
package.)

>In response to
>
>int	x, y;
>while (...)
>	scanf("%d, %d", &x, &y);
>
>if I type 'a' on the keyboard, why
>does the loop keep running, skipping over the scanf ?

Scanf's most miserable problem is that it doesn't discard
unrecognized input.  (This is a documented feature, so don't try
getting it changed.  It is only a miserable problem when scanf
is being used for interactive user input, which is what everybody
uses it for.)  The 'a' sits there in the input buffer, causing
each scanf to fail, and the correct digits you probably typed
after the 'a' are never seen.

If you're writing a non-toy program, one that should deal
gracefully with incorrect user input, the best way of handling it
is to read an entire line of text with fgets, then pick it
apart, perhaps with sscanf:

	char line[MAXLINE];
	while (...) {
		fgets(line, MAXLINE, stdin);
		if(sscanf(line, "%d, %d", &x, &y) != 2)
			{error... }
	}

The other thing that will significantly reduce difficulties with
scanf et al is to check the return value, as I did in the example
above.  If scanf isn't able to convert the number of items
requested, something is wrong, and to continue without
complaining or correcting it is invariably folly.

                                            Steve Summit
                                            scs at adam.pika.mit.edu

P.S. Two other relevant reminders:
     1.	Do use fgets, not gets, because fgets lets you announce
	your buffer size and prevent overflow.
     2.	Remember to pass addresses to *scanf (burkie did, but
	forgetting to is a common problem).



More information about the Comp.lang.c mailing list