tags:

views:

115

answers:

5

Hello, i write a little code to simply read a char from the keyboard but the program fails, why? How must i read a char?

int main(int argc, char** argv)
{
 char op;

 do
 {
  printf("¿Sigues?");
  scanf("%c",&op);
 }while(op=='s' || op=='S');
 return 0;
}
+1  A: 
op = getc(stdin);
eduffy
Thank you very much,Can you explain me the difference between them?
Vaul
@eduffy - the loop in the original post will produce the same result as the `scanf("%c")`. `getc(stdin)` will still only read one char, and there will still be a `\n` in stdin.
BeeBand
+1  A: 

scanf flushes only after reading a newline. it cant be done in platform independent way

vinothkr
A: 

Try this

int main(int argc, char** argv)
{
 char op;

 do
 {
  fflush(stdin);
  printf("¿Sigues?");
  scanf("%c",&op);
 }while(op=='s' || op=='S');
 return 0;
}
kaustubh
`fflush()` is not defined for input streams.
John Bode
hmmm.. I know it's defined only for output streams, but i'm yet to find an example where this doesn't work correctly. And besides, does there actually exist a real portable way to achieve exactly same effect?
kaustubh
@kaustbuh - it may *appear* to "work correctly", but there are no guarantees. The only portable way to clear the input stream is to read from the input stream until you find a `\n` (or hit EOF).
John Bode
+1  A: 

Your problem is that the %c conversion specifier doesn't cause scanf() to skip leading whitespace. You need to handle the newline character that's still in the stream after reading your input.

The input stream is empty when scanf() is called the first time through the loop, so it waits for you to type something. You type s and hit the Enter key, so the input stream contains the characters s and \n (newline). scanf() removes the s from the input stream and assigns it to op. When scanf() is called the second time, the input stream is not empty; it still has the \n character in it, so scanf() reads it and assigns it to op, which causes the loop condition to fail, so your loop exits.

There are several ways to get around this problem. I'm going to recommend reading strings as opposed to individual characters using fgets(), as follows:

char op[3] = {0}; // input character + newline character + 0 terminator

do
{
  printf("¿Sigues?");
  if (fgets(op, sizeof op, stdin))
  {
    /**
     * Check for a newline character in the input.  If it's not there
     * then the user typed in too many characters.  In order to keep
     * the input stream from getting clogged up with bad input, read
     * until we find a newline character.
     */
    char tmp[3];
    char *newline = strchr(op, '\n');
    while (!newline && fgets(tmp, sizeof tmp, stdin))
    {
      newline = strchr(tmp, '\n');
    }
  }
  else
  {
    printf("Error while reading input\n");
    op[0] = 0;
  }
} while (tolower(op[0]) == 's');
John Bode
That's it, thank you very much, for the explanation too.
Vaul
A: 

You're seeing the line "Sigues" twice because there's a \n still in the input stream. If you type in a character and hit enter there are now two characters in your input stream. Your scanf formatter only specifies one char, so scanf reads in one char and then advances. However, the next character in the stream is a \n, hence the exit from the loop on the second go.

NB. @eduffy's technique of getc(stdin) will do the exact same thing, there's still a \n in stdin. You need to advance past that \n somehow.

How about reading in your char, and then chomping the rest of the stream up to the \n char? I tried this and it works for me:

char op;

do
 {
  printf("¿Sigues?");
  scanf("%c",&op);
  while(getchar() != '\n') continue;
}while(op=='s'|| op=='S');
BeeBand