为什么我们使用 scanf() 却需要 getchar()?

Why we need getchar() although using scanf()?

这段代码应该读取一个正数,如果用户输入一个非数字值,它会要求他再次输入一个数字并等待输入再次检查直到输入一个数字

 do
   {
        printf("Enter a positive number: ");
   }
  while ( (scanf("%d%c", &n,&c) != 2 || c!='\n' || n<0) ) ;

但实际上当输入非数字时,它会继续执行 while 循环的主体而不读取等待检查 while 循环的条件 while(scanf("%d%c", &n,&c) != 2 || c!='\n' || n<0)

将条件编辑为

int clean_stdin()
{
    while (getchar()!='\n');
    return 1;
}

 do
   {
        printf("Enter a positive number: ");
   }
  while ( (scanf("%d%c", &n,&c) != 2 || c!='\n' || n<0) && clean_stdin() ) ;

它以正确的方式执行,但我不明白为什么我们需要添加 getchar() 虽然我们已经在条件

中使用了 scanf()

因为大多数说明符的 scanf() 会忽略空格,如果 '\n' 留在缓冲区中,您需要在再次调用 scanf() 之前收集它们。如果您不收集它们(并立即丢弃它们),那么 scanf() 将在下一次调用时立即 return。

查看此代码

#include <stdio.h>

int
main(int argc, char* argv[]) {
  char c = 0;
  scanf("%c", &c);
  printf("%c\n", c);
  scanf("%c", &c);
  printf("%c\n", c);
  return 0;
}

如果您输入的字符超过两个或三个,第二次调用 scanf 将不会产生干扰。而且 getch() 不是标准的。另外你不应该调用 getchar() 因为它可能会阻塞。 您可以使用 fseek

使用 fseek 的 Hack 仅适用于 Windows。 :-(

糟糕的解决方案

#include <stdio.h>

int
main(int argc, char* argv[]) {
  char c = 0;
  scanf("%c", &c);
  printf("%c\n", c);
  fseek(stdin, 0, SEEK_END);
  scanf("%c", &c);
  printf("%c\n", c);
  return 0;
}

好的解决方案

#include <stdio.h>

int
main(int argc, char* argv[]) {
  char buf[BUFSIZ];
  char c = 0;
  scanf("%c", &c);
  printf("%c\n", c);
  while (!feof(stdin) && getchar() != '\n');
  scanf("%c", &c);
  printf("%c\n", c);
  return 0;
}

这适用于 Windows & Linux

考虑使用 fgets 收集输入。任何无效输入都已从输入流中删除,使重试变得更简单。
根据需要使用 sscanf 或其他解析输入。

char input[40] = "";
int valid = 0;
int n = 0;

do {
    printf ( "Enter a positive integer\n");
    if ( fgets ( input, sizeof ( input), stdin)) {
        int last = 0;
        if ( 1 == ( valid = sscanf ( input, "%d%n", &n, &last))) {
            if ( n < 0  || input[last] != '\n') {
                valid = 0;//reset if negative or last is not newline
            }
        }
    }
    else {
        fprintf ( stderr, "problem getting input from fgets\n");
        return 0;
    }
} while ( valid != 1);

scanf("%d%c", ... 遇到非数字输入时,"%d" 会导致扫描停止,违规字符将保留在stdin 中以供下一个输入函数使用。 "%c" 没有机会读取该非数字字符。

如果代码用相同的 scanf("%d%c", ... 重新读取 stdin,结果相同。需要一些 other 方法来删​​除非数字输入。 getchar()getch() 等将读取任意 1 个字符。