问题
Well I been doing a lot of searching on google and on here about how to flush the input stream properly. All I hear is mixed arguments about how fflush() is undefined for the input stream, and some say just do it that way, and others just say don't do it, I haven't had much luck on finding a clear efficient/proper way of doing so, that the majority of people agree on.. I am quite new at programming so I don't know all the syntax/tricks of the language yet, so my question which way is the most efficient/proper solution to clearing the C input stream??
Use the
getchar()
twice before I try to receive more input?Just use the
fflush()
function on the input? orThis is how I thought I should do it.
void clearInputBuf(void); void clearInputBuf(void) { int garbageCollector; while ((garbageCollector = getchar()) != '\n' && garbageCollector != EOF) {} }
So, whenever I need to read a new scanf(), or use getchar() to pause the program I just call the clearInputBuf.. So what would be the best way out of the three solutions or is there a even better option?
回答1:
All I hear is mixed arguments about how fflush() is undefined for the input stream
That's correct. Don't use fflush()
to flush an input stream.
(A) will work for simple cases where you leave single character in the input stream (such as scanf()
leaving a newline).
(B) Don't use. It's defined on some platforms. But don't rely on what standard calls undefined behaviour.
(C) Clearly the best out of the 3 options as it can "flush" any number of characters in the input stream.
But if you read lines (such as using fgets()
), you'll probably have much less need to clear input streams.
回答2:
It depends on what you think of as "flushing an input stream".
For output streams, the flush operation makes sure that all data that were written to the stream but were being kept buffered in memory have been flushed to the underlying filesystem file. That's a very well defined operation.
For input streams, there is no well defined operation of what flushing the stream should do. I would say that it does not make any sense.
Some implementations of the C standard library redefine the meaning of "flush" for input streams to mean "clear the rest of the current line which has not been read yet". But that's entirely arbitrary, and other implementations choose to do nothing instead.
As of C11 this disparity has been corrected, and the standard now explicitly states that the fflush()
function does not work with input streams, precisely because it makes no sense, and we do not want each runtime library vendor to go implementing it in whatever way they feel like.
So, please by all means do go ahead and implement your clearInputBuf() function the way you did, but do not think of it as "flushing the input stream". There is no such thing.
回答3:
It turns out to be platform dependent.
The fflush()
cannot have an input stream as a parameter because according to the c standard, IT'S UNDEFINED BEHAVIOR since the behavior is not defined anywhere.
On Windows, there is a defined behavior for
fflush()
and it does what you need it to do.On Linux, there is fpurge(3) which does what you want it to do too.
The best way is to simply read all characters in a loop until
- A newline character is found.
EOF
is returned fromgetchar()
.
like your clearInputBuf()
function.
Note that flushing an output stream means writing all unwritten data to the stream, the data that is still in a buffer waiting to be flushed. But reading all the unread bytes from a stream, does not have the same meaning.
That's why it doesn't make sense to fflush()
an input stream. On the other hand fpurge()
is designed specifically for this, and it's name is a better choice because you want to clear the input stream and start fresh. The problem is, it's not a standard function.
Reading fpurge(3) should clarify why fflush(stdin)
is undefined behavior, and why an implementation like the one on Windows doesn't make sense because it makes fflush()
behave differently with different inputs. That's like making c compliant with PHP.
回答4:
The problem is more subtile than it looks:
On systems with elaborate terminal devices, such as unix and OS/X, input from the terminal is buffered at 2 separate levels: the system terminal uses a buffer to handle line editing, from just correcting input with backspace to full line editing with cursor and control keys. This is called cooked mode. A full line of input is buffered in the system until the enter key is typed or the end-of-file key combination is entered.
The
FILE
functions perform their own buffering, which is line buffered by default for streams associated with a terminal. The buffer size in set toBUFSIZ
by default and bytes are requested from the system when the buffered contents have been consumed. For most requests, a full line will be read from the system into the stream buffer, but in some cases such as when the buffer is full, only part of the line will have been read from the system whenscanf()
returns. This is why discarding the contents of the stream buffer might not always suffice.
Flushing the input buffer may mean different things:
discarding extra input, including the newline character, that have been entered by the user in response to input requests such as
getchar()
,fgets()
orscanf()
. The need for flushing this input is especially obvious in the case ofscanf()
because most format lines will not cause the newline to be consumed.discarding any pending input and waiting for the user to hit a key.
You can implement a fluch function portably for the first case:
int flush_stream(FILE *fp) {
int c;
while ((c = getc(fp)) != EOF && c != '\n')
continue;
return c;
}
And this is exactly what your clearInputBuf()
function does for stdin
.
For the second case, there is no portable solution, and system specific methods are non trivial.
来源:https://stackoverflow.com/questions/40958298/is-this-the-proper-way-to-flush-the-c-input-stream