From: j DOT aldrich6 AT genie DOT com Message-Id: <199607120458.AA205067505@relay1.geis.com> Date: Fri, 12 Jul 96 04:17:00 UTC 0000 To: lehmann AT mathematik DOT th-darmstadt DOT de Cc: djgpp AT delorie DOT com, norbertj AT panix DOT com Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii Subject: Re: Beating fflush to death Reply to message 8794437 from LEHMANN AT MATHE on 07/11/96 9:56AM >: My how to write C books says that SOMETIMES scanf leaves a newline >: character behind in the buffer. The book suggests fflush(stdin) which as >: we all know does not work. I use gets(dum) (char dum[1]) to clear the >: buffer after each scanf fpr this particular program. Your C book ought to explain exactly why this is so. The reason is related to the way in which scanf() reads input. For each format specifier, scanf() reads the input stream until it finds an invalid character or a whitespace character (space, tab, newline), at which point it stops reading, *leaving that character still in the buffer*. For example, suppose you had a statement like: scanf( "%d%d", &n1, &n2 ); and the user typed this: 55 102[Enter] What your program would get is the string "55 102\n". scanf() reads the first number, stopping at the first whitespace character (the space). Then it starts reading the second number. The first thing it sees is whitespace (the space where it stopped the first time), so it keeps going until it sees a non-whitespace character (the '1'). Then it reads in the second number, stopping at the newline. Thus, the newline is still in the buffer! Now, if you were to immediately issue another call to scanf() right after this one, you'd be ok, because scanf() discards all leading whitespace. But if you called getchar(), you would get back the '\n' that is still in the buffer. And if you called gets() or fgets(), it would see the newline as the end of the string it was told to read and return without waiting for the user to input anything. This is why it is important to "flush" stdin after a call to scanf(). >: 1. Will this work on ALL versions of DOS? If so, why is something like >: it built into the lib? fflush(stdin) is a hackish bit of nonsense introduced by Borland to make things easier for lazy users. According to the ANSI spec, fflush's behavior is only defined for _output_ streams. >gets doesn't check for buffer overruns, so you may overwrite some >other part of your data with this call, if there is more than a single >newline character available. (Remember the Internet worm, that >exploited a similar bug in fingerd to propagate), if you want to use >gets, don't , use fgets instead, it has a buffer size parameter and is >safer. But fgets(), because it stops before overflowing its buffer, may sometimes leave data in the input buffer. You need to check the strings it returns for '\n' before using them. Also, remember that while gets() replaces the '\n' with a null, fgets() leaves it in. It's a significant, though often overlooked, difference. >: 4. Is the inconsistency between systems like DOS - UNIX or is it internal >: to each system Most _systems_ handle i/o streams in the same general fashion. What differs is the _compilers_ you use. As I mentioned above, Borland has introduced a lot of "helpful enhancements" that do not adhere to the ANSI spec. I particularly dislike flushall(), and closeall(). Real programmers should be able to keep track of these things themselves, and besides, there's always sync(). :) >Well, scanf isn't really a function that should be used at all IMHO, I >prefer fgets and fscanf, at least you get a chance to examine the >string in case of an error. Good point. I have stopped using scanf() entirely in my programs because it is too easy for users to make it fail. Simply reading and parsing data myself works far better (and more elegantly, too). At most I may resort to an sscanf() to read data from a string, but that only in limited circumstances. I haven't gotten as far yet as switching to fgets(), but I will as soon as I find an elegant way of handling too- long lines.