7

Since I discovered fflush(stdin) is not a portable way to deal with the familiar problem of "newline lurking in the input buffer",I have been using the following when I have to use scanf:

while((c = getchar()) != '\n' && c != EOF);

But today I stumbled across this line which I had noted from cplusplus.com on fflush:

fflush()...in files open for update (i.e., open for both reading and writting), the stream shall be flushed after an output operation before performing an input operation. This can be done either by repositioning (fseek, fsetpos, rewind) or by calling explicitly fflush

In fact, I have read that before many times.So I want to confirm if I can simply use anyone of the following before the scanf() to serve the same purpose that fflush(stdin) serves when it is supported:

fseek(stdin,1,SEEK_SET);
rewind(stdin);

PS rewind(stdin) seems pretty safe and workable to flush the buffer, am I wrong?

Mistake I should have mentioned fseek(stdin,0,SEEK_SET) if we are talking about stdin as we can't use any offset other than 0 or one returned by ftell() in that case.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Jugni
  • 255
  • 5
  • 12
  • From your quote, "... *the stream shall be flushed after an output operation* ...". Do you expect to be performing output operations on `stdin`, in order to require `fflush(stdin)`? That seems silly! You want to *write* to a *read-only* stream?! Why don't you describe what you mean by *flush the buffer*, or what it is you want `fflush(stdin)` to do? You might also want to consider what `fflush` actually does according to [a non-C++ manual](http://pubs.opengroup.org/onlinepubs/009695399/functions/fflush.html). After all, this is C, not C++... – autistic May 21 '13 at 16:01
  • @undefinedbehaviour That's not my quote.That's taken from http://www.cplusplus.com/reference/cstdio/fflush/ and that speaks about both I/O streams,not `stdin` in particular.What I meant is,when reading from `stdin`,according to that paragraph,we would be able to flush it by using `rewind()` or `fseek()` on it. – Jugni May 21 '13 at 16:08
  • `stdin` is open for reading only, not for update (both reading and writing). Don't confuse these two modes. It's not uncommon for that site to be grossly inaccurate. Find another manual site. I recommend opengroup. – autistic May 21 '13 at 16:17
  • @undefinedbehaviour Well,I never said I intend to write into `stdin`.What I mean is,if there is a newline remaining from previous **Enter** key,then why can't we use `fseek()` and `rewind()` on it(in order to flush it).Do you mean to say **stdin is not seekable**?Is it so? – Jugni May 21 '13 at 16:50
  • No. I mean to say **stdin is not writable**. `fflush` causes data to be **written**. Click on the link in my first comment and you'll see that. There are three modes of access: open for read, open for write and open for update. What do you mean by *flush it*? Define this process without using the word *flush* (because that's gibberish) and you'll see that seek can't help you all that much even when the file is seekable. – autistic May 22 '13 at 02:24
  • I presume you mean "read and discard the remainder of a line (because the user made an error and you want to prompt for corrections, or because you've already extracted the information you need from that line and you don't care about the rest of it)". How does seek or rewind help you do this? Look at the code in the while loop. How does that help you read and discard the remainder of a line? How might `scanf("%*[^\n]"); getchar();` help you read and discard the remainder of a line? – autistic May 22 '13 at 02:32

1 Answers1

4

This is the only portable idiom to use:

while((c = getchar()) != '\n' && c != EOF);

Several threads including this one explain why feesk won't usually work. for much the same reasons I doubt rewind would work either, in fact the man page says it is equivalent to:

(void) fseek(stream, 0L, SEEK_SET)
Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • I read that link you gave.But it seems a little hard to understand.Can you put the portion of that link that is relevant to this question in a few simple lines? – Jugni May 21 '13 at 14:54
  • @Jugni This comment really explain it well http://stackoverflow.com/questions/4917801/using-fseek-with-a-file-pointer-that-points-to-stdin#comment5479013_4917849 basically a stream is not stored anywhere. If you want to seek around the data read it into memory. – Shafik Yaghmour May 21 '13 at 15:07
  • But I read a stream is buffered by default.I am pretty sure `stdin`and `stdout` are buffered.As are all streams opened with `fopen()` – Jugni May 21 '13 at 15:24
  • I mean,generally when we open a file using `fopen()`,it is read into the buffer/memory first as it's faster this way rather than reading writing from the disk each time. – Jugni May 21 '13 at 15:25
  • @Jugni No. The C11 standard says in regards to `fopen` *"When opened, a stream is fully buffered if and only if it can be determined not to refer to an interactive device."* ... and in regards to `fseek` *"For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET."* ... so even if you do have a seekable `stdin` (eg. it was piped from a file), it might be a text stream (like on Windows), and you shouldn't be seeking like in your question... – autistic May 21 '13 at 16:23
  • @undefinedbehaviour Ok, so if I rectify my question and use **0** as the offset from SEEK_SET,why won't seeking be allowed? – Jugni May 21 '13 at 16:52
  • Providing the file is seekable, it'll be allowed... but it won't do what you want it to. – autistic May 22 '13 at 02:20