【问题标题】:Why does scanf get stuck in an infinite loop on invalid input? [duplicate]为什么scanf会在无效输入时陷入无限循环? [复制]
【发布时间】:2013-05-28 18:18:22
【问题描述】:

在第 5 行中,我读取了一个整数,isint 如果读取的是整数,则为 1,如果不是整数,则为 0。如果isint 为 0,我有一个循环要求用户提供一个整数,我会一直阅读直到用户提供一个整数。我尝试这段代码给出一个字符而不是一个整数,但我有一个无限循环。该程序只是不等待提供新的输入。我的代码有什么问题?

#include <stdio.h>

int main(void) {

  int arg1;
  //int arg2;
  int attacknum = 1;
  int isint = 1;

  //printf("Insert argument attacks and press 0 when you have done this.\n");
  printf("Attack %d\n", attacknum);
  attacknum++;
  printf("Give attacking argument:");
  isint = scanf("%d", &arg1);  //line 5

  while(isint == 0){
    printf("You did not enter a number. Please enter an argument's number\n");
    isint = scanf("%d", &arg1);
    printf("is int is %d\n", isint);
  }
  return 0;
}

【问题讨论】:

  • printf("is int is %d\n",isint) 的输出是什么?
  • 请提供您的场景的控制台输出。

标签: c scanf stdio


【解决方案1】:

正如其他人所提到的,如果scanf 无法解析输入,它就会使其无法扫描。

由于这种行为,通常scanf 不适合交互式输入,并且与用户体验的一次一行的界面不匹配。

最好使用fgets 将一行读入缓冲区。然后使用sscanf 解析该行。如果您不喜欢输入,请将整行扔掉并阅读另一行。

类似这样的:

#include <stdio.h>

int main(void)
{
  char line[256];

  int arg1;
  int isint;

  while (1) {
    printf("Give attacking argument:");
    fgets(line, sizeof line, stdin);
    isint = sscanf(line, "%d",&arg1);
    if (isint) break;

    printf("You did not enter a number.Please enter an argument's number\n");
  }

  printf("Thanks for entering %d\n", arg1);

  return 0;
}

(对于生产代码,您需要处理长行,检查返回码,还要检查数字后面的尾随垃圾等)

实际上,如果您只想读取整数,不使用scanf,而使用strtol 是一种更好的方法。这为您提供了一个方便的指针,指向数字后面的字符,您可以检查它是空格还是 nul。

【讨论】:

  • 这仍将接受123ab 之类的输入作为123。使用 for 循环在行内搜索无效字符是个好主意,请在此处查看相同的问题:stackoverflow.com/questions/20829672/…
  • 检测是否有尾随垃圾是个好主意。如在那个问题中那样,通过手动扫描字符串来做到这一点是一种非常冗长且不雅的方式。最好只使用strtol,它会给你一个指向下一个字符的指针。
【解决方案2】:

scanf 遇到非数字时,它不会消耗任何输入并返回读取的零整数。非数字将保留在输入中,以便下次调用 scanf,其行为与第一次调用相同,等等。

在下面回答您的问题。您可以使用fgetc 解析至少一个字符,但这会为每个已键入的字符提供错误消息。通常我认为你想跳到换行符。为此,您可以按照 poolie 的建议使用fgets。或者您可以在scanf 之后添加以下内容。

int ch;
if (isint == 0)
while ((ch = fgetc(stdin)) != EOF && ch != '\n')
{
     /* Skip characters */
}

P.S:在您的情况下,最好将它放在循环中的第一个 printf 之前。

【讨论】:

  • 你有什么建议来解决这个问题?我如何消费非数字?
  • @Dchris 我添加了一些建议。
  • @Dchris 你做过哪些研究?你对这个问题是认真的吗?你为什么不看书?
  • @poolie:和其他编辑愉快的手指:感谢您修复变量名称,但您也可以发表评论。但是请注意,这种编码风格是故意的,所以请不要更改它。
  • 我本可以发表评论,但编辑似乎更简单,噪音更小,而且似乎符合 SO 的 wiki 本质精神。还有那种编码风格……好吧,你可以选择,但这很不寻常,你能怪我认为这也是一个错字吗? No need to be rude.
猜你喜欢
  • 2010-11-01
  • 2013-10-29
  • 1970-01-01
  • 2019-12-23
  • 2020-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
相关资源
最近更新 更多