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 > 0false0 < 15truefalse && truefalse!falsetrue 。 这就是它无限循环的原因。