输入不匹配的字符串时,Scanf 无法在 while 循环中工作

Scanf not working in while loop when nonmatching string is entered

我正在使用一个名为 checkType 的函数来检查用户是否输入了有效的整数类型输入。例如,如果用户输入 15,它将打印 valid,而 15c 将打印 not valid。但是,如果用户只输入像ccccc这样的字符串输入,就会导致死循环,程序崩溃。我在下面添加了一些屏幕截图来显示输出。

int checkType(int input, char *c) {
  if (input == 2 and *c == '\n') {
    return 1;
  } else {
    return 0;
  };
}

int main(void) {
  int faces = 0;
  char c;
  int valid = 0;
  int input;

  while (valid == 0) {
    printf("Enter number of faces: ");
    input = scanf("%d%c", &faces, &c);
    valid = checkType(input, &c);
    printf(valid == 0 ? "not valid\n" : "valid\n");
  }
}

无限循环:

scanf() 函数族并不是真正为输入有问题的语法而设计的。

解决问题的常用方法是以一定会成功的方式读入所有输入,例如通过使用 fgets() 读取完整的一行(而不是数字、类似单词的字符串或任何其他具有预期格式的内容)。 然后您可以尝试按照预期格式解析该行表示字符串。 (您可以使用 sscanf() 进行解析尝试。)如果失败,您将忽略它并阅读下一行,或者尝试根据相同输入的替代允许格式进行解析。

相关区别在于读取整行会成功并将其从输入流中移除。与此相反,如果出现语法错误,您的代码会在输入流中留下任何与预期语法不匹配的内容。因此,它当然会再次失败读取循环的下一次迭代。这就是导致无限循环的原因。

详细:

  • 将整行读入缓冲区,
    使用 fgets() 和将字符数限制为缓冲区大小的选项
  • 此时所有行都从输入中删除(又名标准输入,又名输入流),
    这意味着即使读取的行不匹配任何允许的格式,下一次读取也会获得新的输入,
    这是与尝试使用 scanf()
  • 直接读取输入的相关区别
  • 从行缓冲区中,尝试根据允许的格式读取单独的值,
    使用 sscanf() 并检查 return 值
  • 如果成功很好,你已经填充了预期的变量(例如整数);
    您可以尝试扫描额外的、未覆盖格式的尾随输入(并继续检查不正确的输入,即使行的开头匹配允许的格式)
  • 如果不成功,请尝试不同的允许格式,
    再次使用 sscanf()
    来自同一行缓冲区,即使格式部分匹配也不会更改
  • 如果没有允许的格式与输入相匹配,则认为它不正确
  • 不正确的输入可以被忽略或者会在你的程序中导致致命的解析错误,你的选择

However, if the user enters a string input only like ccccc,
it results in an infinite loop and the program crashes

原因:scanf returns 来自 stdin 的有效读取值的数量。如果我们给 cccc 作为输入, scanf 无法读取值,因为输入和变量 faces 是不同的数据类型。这使得 input = 0。所以函数 checkType returns 0,这反过来使得 valid = 0。这使得 while(valid == 0) 始终为真,因此无限循环。

Scanf 将从标准输入中读取,如果不匹配则不清除标准输入缓冲区。所以在你的情况下它会再次读取错误的数据,你可以在 scanf 之后添加一个带有 stdin 的干净函数,比如:__fpurge(stdin)

您可以参考以下两个链接:

https://man7.org/linux/man-pages/man3/scanf.3.html

http://c-faq.com/stdio/stdinflush2.html

对于 "ccccc"scanf("%d%c" ... 这样的输入,不会转换为 intscanf() returns 0 stdin保持不变。再次调用该函数结果相同。

代码需要以某种方式消耗错误的输入。

研究 fgets() 以阅读 用户输入。