Scanf和循环
这里是一段代码,它应该循环遍历,直到用户输入0到15之间的数字
int input; do { printf("Enter a number => "); scanf("%d",&input); printf("\n %d \n",input); } while (!(input>0 && input <15));
但是,如果用户输入类似“gfggdf”的内容,则会导致循环重复一遍又一遍,并且从不提示用户再次输入…控制台看起来像这样
Enter a number => 0 Enter a number => 0 Enter a number => 0 Enter a number => 0 Enter a number => 0 Enter a number => 0 (looping indefinitely)
看完这本书后,似乎我需要做这样的事情来防止这种情况发生。
int input, error, status; char skip_ch; do { error = 0; printf("Enter a number => "); status = scanf("%d",&input); printf("\n %d \n",input); if(status!=1) { error=1; } else if(input 15){ error = 1; } do { scanf("%c",&skip_ch); }while(skip_ch != '\n'); } while (error);
我理解需要检查scanf状态以确保它是有效输入,我不明白内部do-while循环。 我觉得这本书从来没有真正向我解释为什么需要多次调用scanf,就像扫描缓冲区填充了一堆垃圾一样,它只是通过循环遍历它一百万次来清理它。您。
有谁可以向我解释这个黑魔法?
原始代码无限循环,因为当scanf无法将其转换为整数时,无法从输入缓冲区中删除无效数据(“gfggdf”) – 它留在输入缓冲区中,因此下一次调用scanf看起来相同数据,(当然)仍然无法将其转换为整数,因此循环再次执行,结果仍然没有改变。
的:
do { scanf("%c",&skip_ch); }while(skip_ch != '\n');
只需一次读取一个字符(并忽略它),直到它到达行尾。 如果你想在没有循环的情况下去除输入缓冲区中的垃圾,你可以使用类似: scanf("%*[^\n]");
另一种可能(可能更多)广泛使用的可能性是从读取整行开始,然后尝试转换行中的内容。 无论是否转换,您已经读取了所有数据到行尾,因此无论转换是否有效,下一行读取/转换的下一次尝试都将从下一行开始。 这确实有一个潜在的缺点:如果你有一个很长的输入线,你最终可能会阅读并存储大量你没有实际用途的数据。 这很少是一件大事,但你仍然应该意识到这一点。
这就是为什么有很多类似问题的答案,建议不要使用scanf()
。
此外,您应该检查scanf()
的返回值,因为它会告诉您何时出现错误 – 并且无法转换任何值。
通常推荐的解决方案是fgets()
读取输入行和sscanf()
的组合,一旦读取就解析行。
示例中的第二个循环用于读取字符,包括换行符,从而重新同步scanf()
并跳过任何虚假数据。 这是一种冗长的做法; 使用getchar()
会更简单:
int c; while ((c = getchar()) != EOF && c != '\n') ;
注意使用’ int c;
‘ – 类型关键不是’ char
‘或’ unsigned char
‘,因为它必须存储所有可能的char
值加EOF。
首先,避免使用scanf()
,而是使用fgets()
。
评估您的情况(第一个代码)。 0 > 0
为false
。 0 < 15
是true
。 false && true
是false
。 !false
是true
。 这就是它无限循环的原因。