问题描述:
我先来描述一下问题,也就是常遇到的情形。
程序如下所示,我们应该在程序运行到scanf 位置的时候,输入数字。 如果是输入数字,那么可以得到对应结果。 可是如果输入有误,不小心输入了一个字符串或者其他非数值类内容,该程序就直接崩溃陷入了死循环。
示例代码:
// 程序运行环境: ubuntu 18.04 gcc 7.5.0 c语言
#include <stdio.h>
int main()
{
int week;
while(1)
{
scanf("%d", &week);
if( week > 7 || week < 1 )
printf("Out of range~\n");
switch(week)
{
case 1: printf("Monday\n"); break;
case 2: printf("Tuesday\n"); break;
case 3 ... 7: printf("Happy day\n"); break;
default: printf("Other day"); break;
}
}
printf("over\n");
return 0;
}
编译及运行结果
:~$ gcc example.c -o exam
:~$ ./exam
3 //输入3
Happy day //执行结果
1 //输入1
Monday // 执行结果
hello // 输入 hello
Monday
Monday // 陷入死循环
Monday
Monday
.....
问题原因:
那么出现问题的原因是什么呢?
在《C Primer Plus》中,详细给读者解释了 scanf 的特性。
scanf依据一个%d转换说明读取一个整数时,每次读取一个字符,跳过所有空白字符,直到读取到第一个空白字符才开始读取,因为要读取整数,所以scanf希望发现一个数字字符或者一个符号(+或-),如果找到一个数字或符号,它便保存该字符,并读取下一个字符,直到遇到非数字字符便认为读到了整数的结尾,然后scanf将非数字字符放回输入流,这意味着在下次读取输入时,首先读到的是上次读取丢弃的非数字字符。
找到了问题出现的原因。我们就可以去着手解决问题。
解决方案:
在每次调用scanf之后,调用下面这个函数。 也就是在下次读取输入之前,先将之丢弃的非数字字符,读取出来。相当于刷新了输入流,或者说在下次读取之前,先清空了输入流。
// 程序运行环境: ubuntu 18.04 gcc 7.5.0 c语言
void clean_ch()
{
while ( getchar() != '\n' ) { ; } //空语句。 循环的目的只有一个,将所有字符读走。
}
还有很多函数(类似的功能)都可以实现相同的效果,比如:
// 程序运行环境: ubuntu 18.04 gcc 7.5.0 c语言
rewind(stdin); //功能: 将文件内部的位置指针重新指向一个流(数据流/文件)的开头(注意:不是文件指针而是文件内部的位置指针)
fseek(stdin, 0L, SEEK_SET); // 功能rewind.
fflush(stdin); // 刷新输入流
...
问题的原因找到,就有很多方式可以解决。
有不完善的地方,欢迎读到的小伙伴给与批评与指正,欢迎交流探讨。