scanf失败为什么?

当我写这个,编译和运行:

int x; scanf ("%d", &x); while (x!=4) { scanf ("%d", &x); } 

当插入字符或小于4的双数时,input一个无限循环。
当插入大于4的双倍时,它终止。
任何解释?

从C语言标准(n1256) :

7.19.6.2 fscanf函数

4 fscanf函数依次执行格式的每个指令。 如果指令失败,如下所述,函数返回。 故障被描述为input故障(由于发生编码错误或input字符不可用)或匹配故障(由于不适当的input)。

7作为转换规范的指令定义了一组匹配的input序列,如下所述每个说明符。 转换规范在以下步骤中执行:

8input空格字符(由isspace函数指定)将被跳过,除非规范包含[cn说明符。 250)

9从stream中读取input项目,除非规范包含n说明符。 input项被定义为input字符的最长序列,其不超过任何指定的字段宽度,并且是匹配input序列的或者是匹配input序列的前缀。 251)input项目保持未读状态后的第一个字符(如果有的话 。 如果input项的长度为零,则指令的执行失败; 除非文件结束,编码错误或读取错误阻止了来自stream的input,否则这种情况是匹配失败,在这种情况下,这是input失败。

10除了说明符的情况外,input项目(或者在%n指令的情况下,input字符的计数)被转换为适合于转换说明符的types。 如果input项目不匹配,则指令的执行失败:这种情况是匹配失败。 除非由*指示分配抑制,否则转换的结果将放置在尚未收到转换结果的format参数后面的第一个参数指向的对象中。 如果此对象没有适当的types,或者如果转换的结果不能在对象中表示,则行为是未定义的。

在第10段中增加了强调。 %d转换说明符需要将input文本格式化为十进制整数。 如果不是,则转换失败,导致转换失败的字符将保留在inputstream中。 使用%d转换说明符进一步调用scanf()将会阻塞相同的字符。

scanf()返回成功分配的数量; 你需要检查这个结果,看看转换是否成功,如下所示:

 int x = 0; while (x != 4) { int result = scanf("%d", &x); if (result != 1) { printf("Last call to scanf() failed; exiting\n"); break; } } 

不幸的是,在inputstream中仍然存在糟糕的input。 有一些处理这个问题的策略。 您可以使用getchar删除违规的字符,然后重试:

 while (x != 4) { int tmp; if (scanf("%d", &tmp) == 0) getchar(); else x = tmp; } 

或者你可以尝试阅读下一个换行符,假设所有剩余的input是b0rked:

 while (x != 4) { int tmp; if (scanf("%d", &tmp) == 0) while (getchar() != '\n') ; else x = tmp; } 

或者你可以尝试读取input为文本,并使用strtol() (我的首选技术)转换为整数:

 char input[SOME_SIZE]; int x = 0; ... while (x != 4) { if (fgets(input, sizeof input, stdin)) { char *check; int tmp = (int) strtol(input, &check, 10); if (!isspace(*check) && *check != 0) { printf("%s is not a valid integer: try again\n", input); } else { x = tmp; } } else { printf("Read error on standard input\n"); break; } } 

这是更多的工作,但它可以让你在分配给x 之前捕捉不好的input。

你不检查scanf是否成功,因此你会遇到错误。 每个循环, scanf将尝试读取和失败。

scanf返回成功读取的项目数,因此修改循环为这样的事情while (x!=4) { if (scanf("%d",&x) != 1) break; } while (x!=4) { if (scanf("%d",&x) != 1) break; }

当scanf停止在inputstream中的特定位置扫描时,它将永远不会前进stream,所以下一个scanf将再次尝试相同的错误…再次…并且再次

input:42 23 foo ...
 scanf:^
 x 42
 scanf:^
 x 23
 scanf:^
 x无法使用
 scanf:^
 x无法使用
 scanf:^
 x无法使用
 scanf:^
 x无法使用
 scanf:^
 x无法使用

你传递给scanf的%d告诉它parsing一个int。 当你input一个double时,它不能parsing既不将分析的数据存储在xvariables中,因为double在32位机器上使用64位而在32位上使用int,从而产生一个Seg。 故障或随机附带影响。