Alien has asked for the wisdom of the Perl Monks concerning the following question:

Hey monks!
I was coding a little program in C and i got stuck on something.
#include <stdio.h> int main() { char answer=' '; printf("(F)irst,(S)econd,(T)hird\n"); scanf("%c",&answer); while(answer !='F' && answer !='S' && answer !='T') { printf("(F)irst,(S)econd,(T)hird\n"); scanf("%c",&answer); } return 0; }
If I enter something different than F,S or T , I get the message "(F)irst,(S)econd,(T)hird" printed more than it should.
I ran the code in gdb and the scanf line is skipped once before it's executed.In perl ,the code :
my $ans; print "(F)irst,(S)econd,(T)hird\n"; chomp($ans=<STDIN>); while($ans ne 'F' && $ans ne 'S' && $ans ne 'T') { print "(F)irst,(S)econd,(T)hird\n"; chomp($ans=<STDIN>); }
runs just fine .
I'm guessing it's something about buffering , but I'm not sure.

Replies are listed 'Best First'.
Re: Why does perl get this right and C doesn't ?
by Joost (Canon) on Nov 28, 2007 at 21:26 UTC
    I'm guessing it's something about buffering , but I'm not sure.
    It isn't. Note that you're doing chomp($ans=<STDIN>); in your perl code, while you're not doing anything like that in the C code.
    #include <stdio.h> int main() { char answer=' '; printf("(F)irst,(S)econd,(T)hird\n"); scanf("%c",&answer); while(answer !='F' && answer !='S' && answer !='T') { printf("answer was: '%c', which is not what I want\n",answer); printf("(F)irst,(S)econd,(T)hird\n"); scanf("%c",&answer); } return 0; }
    Gives:
    $ ./a.out (F)irst,(S)econd,(T)hird a answer was: 'a', which is not what I want (F)irst,(S)econd,(T)hird answer was: ' ', which is not what I want (F)irst,(S)econd,(T)hird
Re: Why does perl get this right and C doesn't ?
by Fletch (Bishop) on Nov 28, 2007 at 21:27 UTC

    Off the cuff my guess is that your perl code handles the newline you're getting (since you don't do anything visible in your C source to put the tty in raw mode) by tossing it with chomp; the C code doesn't do anything about newlines so your first call gets the letter you've pressed, the second call gets the newline that's sitting in the input buffer.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Why does perl get this right and C doesn't ?
by tuxz0r (Pilgrim) on Nov 28, 2007 at 22:38 UTC
    Use:
    char answer[1024]; ... scanf("%s\n", answer); ...
    Using %c suppresses the skipping of whitespace charaters in a scanf, which is causing your newline to get read by subsequenet scanf calls in the while, throwing off your expected results. Plus, using %s lets you more easily handle ANY line of input, since you can then strip leading, trailing white space and more to get the character you want (meaning you'll have to change your check for characters in the while).

    ---
    echo S 1 [ Y V U | perl -ane 'print reverse map { $_ = chr(ord($_)-1) } @F;'
    Warning: Any code posted by tuxz0r is untested, unless otherwise stated, and is used at your own risk.