peek at stdin, flush stdin

Discussion in 'C Programming' started by Johnathan Doe, May 15, 2004.

  1. I'm trying to find a way to reliably peek at stdin, and if anything's
    waiting, flush stdin so that it clears the stream ready to wait for a
    character.

    The problem I have is that in an application, if I call say scanf() to
    get some input, occasionally the newline is still left hanging around in
    the buffer. If there's any junk left over in stdin after getting input
    I'd like to clear it out. And then when going to read input again
    later, check for any junk and clear it out before prompting and
    attempting to read input.

    I've found a way to do this quite well by using:

    scanf("%c%*c", &ch);

    which gets a menu choice of a single character, and sucks up the newline
    still in the stream. But, if any extra stuff is entered, this is not
    very robust. It's all still left in the input stream. Because most of
    my programs run in blocking mode, I can sit there in a loop and read
    everything until stdin drains out. I've tried going into non-blocking
    mode to "peek" at anything that might be there, get it, and then return,
    but I couldn't make it work. It also seems like a bit of a nasty hack.

    Any ideas?

    Many thanks for your help.

    Johnathan
    Johnathan Doe, May 15, 2004
    #1
    1. Advertising

  2. Johnathan Doe wrote:
    > I'm trying to find a way to reliably peek at stdin, and if anything's
    > waiting, flush stdin so that it clears the stream ready to wait for a
    > character.


    char c;
    scanf("%c%*[^\n]%*c", &c);

    Should do the trick. It does not clear stdin if more than
    one line was entered in some way.

    --
    Thomas.
    Thomas stegen, May 15, 2004
    #2
    1. Advertising

  3. Johnathan Doe

    Chris Torek Guest

    >Johnathan Doe wrote:
    >> I'm trying to find a way to reliably peek at stdin, and if anything's
    >> waiting, flush stdin so that it clears the stream ready to wait for a
    >> character.


    In article <news:>
    Thomas stegen <> suggests:
    >char c;
    >scanf("%c%*[^\n]%*c", &c);
    >
    >Should do the trick. It does not clear stdin if more than
    >one line was entered in some way.


    Unfortunately, this technique does not work *unless* there is
    at least one character other than newline following the one
    desired input character. The reason is that the %[ directive
    ("%*[^\n]" => scan an unlimited length sequence of characters
    other than newline, discarding each character scanned) fails
    if the number of characters that match the scanset is zero.

    In other words, scanning an input stream containing "y\n" puts the
    'y' into c, then finds a newline and fails the %[ directive, and
    then stops (and scanf() returns 1 -- one successful convert and
    assign occurred). The newline remains in the stream. If the stream
    contains "yes\n", on the other hand, the %c converts the 'y' as
    desired, the %[ skips the 'e' and 's' as desired, than the %*c
    discards the newline as desired. (Here scanf() again returns 1.)

    The trick is to separate this into *two* scanf() calls:

    r1 = scanf("%c%*[^\n]", &c);
    r2 = scanf("%*c");

    If it ever gets anything at all, the second scanf() just gets one
    newline character, so it can be replaced with getchar(). The return
    value from the first scanf() should be inspected first, to make
    sure that the stream has not already hit end-of-file.

    These all have a flaw: if the character stuck into "c" is a newline,
    they read one more line, so you actually need *three* scanf() calls:

    r1 = scanf("%c", &c);
    ... check for EOF and newline; if not ...
    r2 = scanf("%*[^\n]"); /* read and discard all non-newlines */
    if (r2 != EOF)
    r3 = scanf("%*c"); /* then read and discard the newline */

    A tiny function that calls getchar() in a loop may be more readable
    to future programmers:

    int get_one_letter_response_on_a_line(void) {
    int c, first;

    /* get and save the first character */
    first = c = getchar();

    /* if it was not newline, keep getting more (but stop on EOF) */
    while (c != '\n' && c != EOF)
    c = getchar();

    /* in any case, return the first one, which may be '\n' or EOF */
    return first;
    }

    Now you can just have:

    int c;
    ...
    c = get_one_letter_response_on_a_line();
    switch (c) {
    case 'y': case 'Y': /* handle "yes" */ break;
    case 'n': case 'N': /* handle "no" */ break;
    case EOF: /* handle EOF */ break;
    default: puts("y(es) or n(o), please"); ...
    }

    for instance.
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, May 15, 2004
    #3
  4. Chris Torek wrote:

    [snip]

    WOW, thanks!!! :) :) :)

    --
    Johnathan
    Johnathan Doe, May 23, 2004
    #4
  5. Thomas stegen wrote:

    Thankyou for teaching me about [^\n] : it's not in my textbook!

    Kind Regards.

    > char c;
    > scanf("%c%*[^\n]%*c", &c);
    >
    > Should do the trick. It does not clear stdin if more than
    > one line was entered in some way.
    >
    Johnathan Doe, May 23, 2004
    #5
  6. Johnathan Doe

    Chatoyer

    Joined:
    Oct 26, 2010
    Messages:
    3
    This fine info. came in handy; appropriate question, thank you.
    Chatoyer, May 17, 2013
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jonathan Neill

    Flush stdin?

    Jonathan Neill, Sep 5, 2003, in forum: C Programming
    Replies:
    19
    Views:
    9,383
  2. Fernando Arbeiza

    Will reading from stdin() flush output to stdout()?

    Fernando Arbeiza, Feb 4, 2004, in forum: C Programming
    Replies:
    3
    Views:
    625
    Fernando Arbeiza
    Feb 5, 2004
  3. Darklight

    flush(stdin)

    Darklight, Oct 10, 2004, in forum: C Programming
    Replies:
    11
    Views:
    1,278
    Mark McIntyre
    Oct 12, 2004
  4. Intransition

    Peek at $stdin

    Intransition, Dec 27, 2010, in forum: Ruby
    Replies:
    2
    Views:
    116
    Skye Shaw!@#$
    Dec 27, 2010
  5. Lars Eighner

    How to flush STDIN with getc()?

    Lars Eighner, Aug 6, 2008, in forum: Perl Misc
    Replies:
    8
    Views:
    296
    Peter J. Holzer
    Aug 7, 2008
Loading...

Share This Page