scanf() leaves the new line char in the buffer

2019-09-11 05:47发布

问题:

I have the following program:

int main(int argc, char *argv[])
{
  int a, b;
  char c1, c2;
  printf("Enter something: ");
  scanf("%d",&a); // line 1
  printf("Enter other something: ");
  scanf("%d", &b); // line 2

  printf("Enter a char: ");
  scanf("%c",&c1); // line 3
  printf("Enter another char: ");
  scanf("%c", &c2); // line 4

  printf("Done"); // line 5

  system("PAUSE");

  return 0;
}

As I read in the C book, the author says that scanf() left a new line character in the buffer, therefore, the program does not stop at line 4 for user to enter the data, rather it stores the new line character in c2 and moves to line 5.

Is that right?

However, does this only happen with char data types? Because I did not see this problem with int data types as in line 1, 2, 3. Is it right?

回答1:

The scanf() function removes whitespace automatically before trying to parse conversions other than characters. The character formats (primarily %c; also scan sets %[…] — and %n) are the exception; they don't remove whitespace.

Use " %c" with a leading blank to skip optional white space. Do not use a trailing blank in a scanf() format string.

Note that this still doesn't consume any trailing whitespace left in the input stream, not even to the end of a line, so beware of that if also using getchar() or fgets() on the same input stream. We're just getting scanf to skip over whitespace before conversions, like it does for %d and other non-character conversions.


Note that non-whitespace "directives" (to use POSIX scanf terminology) other than conversions, like the literal text in scanf("order = %d", &order); doesn't skip whitespace either. The literal order has to match the next character to be read.

So you probably want " order = %d" there if you want to skip a newline from the previous line but still require a literal match on a fixed string, like this question.



回答2:

Use scanf(" %c", &c2);. This will solve your problem.



回答3:

Another option (that I got from here) is to read and discard the newline by using the assignment-supression option. To do that, we just put a format to read a character with an asterisk between % and c:

scanf("%d%*c",&a); // line 1
scanf("%c%*c",&c1); // line 3

scanf will then read the next char (that is, the newline) but not assign it to any pointer.

In the end, however, I would second the FAQ's last option:

Or, depending on your requirements, you could also forget about scanf()/getchar(), use fgets() to get a line of text from the user and parse it yourself.



回答4:

Use getchar() before calling second scanf().

scanf("%c", &c1);
getchar();  // <== remove newline
scanf("%c", &c2);


标签: c scanf