Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!rutgers!tut.cis.ohio-state.edu!ucbvax!decwrl!sun-barr!apple!bloom-beacon!adam.pika.mit.edu!scs From: scs@adam.pika.mit.edu (Steve Summit) Newsgroups: comp.lang.c Subject: Re: scanf(..) Message-ID: <11831@bloom-beacon.MIT.EDU> Date: 4 Jun 89 18:20:58 GMT References: <225800176@uxe.cso.uiuc.edu> Sender: daemon@bloom-beacon.MIT.EDU Reply-To: scs@adam.pika.mit.edu (Steve Summit) Lines: 86 In article <225800176@uxe.cso.uiuc.edu> burkie@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@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).