题目:

根据题目写出如下代码1:
#include <stdio.h>
#include <stdlib.h>
int main()
{
const int DAYS_PER_WEEK = 7;
int days = 0, weeks = 0, lefts = 0;
printf("输入天数(<=0时退出):");
scanf("%d", &days);
while (days > 0)
{
weeks = days / DAYS_PER_WEEK;
lefts = days % DAYS_PER_WEEK;
printf("%d天 = %d周%d天\n", days, weeks, lefts);
printf("再次输入天数(<=0时退出):");
scanf("%d", &days);
}
printf("结束!今晚去吃烤肉吧!");
return 0;
}
输入类型正确时(为整型时):程序正常工作:

但当输入类型错误时(非整型)(浮点型或非数字字符时):
输入2.0:
![]()
陷入死循环,只能强制关闭程序:
输入`:
![]()
程序跳过循环直接结束:

输入e:
![]()
同样的, 程序跳过循环直接结束:

这是为什么呢???

这就要看看scanf()函数是怎么工作的了:
以下摘自C Primer Plus:
scanf()函数

如果输入不正确的类型会怎样:

scanf()函数中的格式字符串:

由此我们可以知道,scanf()函数:
1. 一次读取一个字符。
2. 除了%c类型外,会跳过输入值前面的所有空白。
3. 当输入的数据类型错误时,或者说,当scanf()第一次读取到“意料之外”的字符时,会把读到的“意料之外”的字符返回输入,并且禁止后续的scanf()继续读取输入。
而这第三条,就是导致程序bug的原因。
输入浮点数2.0时:
scanf()读取到了2并且将值2填入变量days的地址,并将“意料之外”的字符小数点.返回到输入,并且跳过了后续的scanf()函数。
这就导致变量days的值无法修改,一直保持一定的值,当此值大于0时陷入死循环,小于零时跳出循环结束程序。
输入字符`和e时:
scanf()直接将“意料之外”的字符`或e返回到输入,并且跳过后续的scanf()函数。
这就导致变量days的值无法修改,一直保持一定的值,当此值大于0时陷入死循环,小于零时跳出循环结束程序。
PS:若未对变量days进行初始化,则days的初值是不确定的,是内存中的垃圾值,如果第一次输入的值是符号或者字母,会根据变量days的值决定,当此值大于0时陷入死循环,小于零时跳出循环结束程序。
至此,我们知道了BUG原因,那么如何解决呢?
判断出不合法的输入,给出输出提示,并退出程序
如何实现?这就要用到scanf()函数的返回值了:
以下摘自C Primer Plus:
scanf()函数的返回值:

拓展:副作用和序列点:


通过if()判断scanf()函数的返回值是否为0,来判断输入的数据类型是否正确:
改进后的代码2:
#include <stdio.h>
#include <stdlib.h>
int main()
{
const int DAYS_PER_WEEK = 7;
int days = 0, weeks = 0, lefts = 0;
int test = 0;
printf("输入天数(<=0时退出):");
test = scanf("%d", &days);
if (test == 0)
{
printf("输入类型错误,退出\n");
}
else
{
while (test != 0 && days > 0)
{
weeks = days / DAYS_PER_WEEK;
lefts = days % DAYS_PER_WEEK;
printf("%d天 = %d周%d天\n", days, weeks, lefts);
printf("再次输入天数(<=0时退出):");
test = scanf("%d", &days);
if (test == 0)
{
printf("输入类型错误,退出\n");
}
}
}
printf("结束!今晚去吃烤肉吧!");
return 0;
}
通过变量test获取scanf()的返回值,判断输入类型是否正确并给出提示,以下为运行结果:

成功!
参考文章:
本文分析了C语言中scanf函数在遇到非整型输入时导致的死循环问题,解释了其工作原理,并提供了通过检查scanf返回值来判断并处理输入类型错误的方法,以改进程序的健壮性。
4146

被折叠的 条评论
为什么被折叠?



