关于 scanf(“%d“)输入非数字字符后,陷入死循环的解决方案

问题描述:

我先来描述一下问题,也就是常遇到的情形。
程序如下所示,我们应该在程序运行到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);       // 刷新输入流
...

问题的原因找到,就有很多方式可以解决。
有不完善的地方,欢迎读到的小伙伴给与批评与指正,欢迎交流探讨。

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值