C语言,利用scanf()函数的返回值,判断输入数据类型是否正确

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

题目:

根据题目写出如下代码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()的返回值,判断输入类型是否正确并给出提示,以下为运行结果:

成功! 

参考文章:

http://t.csdn.cn/0Gs2O

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值