C语言由scanf(“%d“,)非法输入字符造成的死循环及其解决方案

声明:此文章仅作为C语言学习历程中的思路整理,用于解决入门阶段较为浅显的问题,如有错误还请指正。

IDE:小熊猫 Dev-C++

现象描述:

代码要求实现用户输入1或2,通过scanf("%d",&a)读取这个值,从而判断分属于1或2的两种情况。输入非1,2的数字都应该返回"Invalid Number!",并且要求重新输入数字。

while(a!=1&&a!=2)
	{
		printf("Invalid Number!\n");
		printf("Enter the number:");
		scanf("%d",&a);
    }


​

该程序在用户输入整数时均可以正常运行,但是一旦用户输入"a","aasa" 时,程序会陷入死循环。死循环和while语句本身没有关系,无论使用while,goto,for,只要是循环体,均会产生此问题。

程序在后续执行中直接跳过应该由用户输入的scanf("%d",&a);

原理分析:

经多方查找资料得,scanf有缓存区,当输入非法字符(要求的类型与输入的类型不符合),scanf会直接跳过,该输入及不会被接受也不会被清除,被存放在scanf的缓存区,当下次调用scanf函数时,会直接从缓存区读取非法字符,造成死循环。

解决思路:

清除滞留在scanf缓存区的数据,使下一次循环时scanf可以正常的读取用户输入。

解决方法:

1.fflush(stdin);

直接使用缓冲区清除函数fflush(stdin); //stdin代表标准输入;

但fflush(stdin)-这个只能保证在VC上可以生效,在其他编译器上不保证可以起作用。

如果在Linux系统中使用gcc编译,该方法不可用。

资料:

在windows VC下fflush(stdin)是可以实现的,但是linux下不可以。 C标准规定fflush()函数是用来刷新输出(stdout)缓存的。对于输入(stdin),它是没有定义的。但是有些编译器也定义了 fflush(stdin )的实现,比如微软的VC。其它编译器是否也定义了 fflush( stdin)的实现应当查找它的手册。GCC编译器没有定义它的实现,所以不能使用 fflush( stdin )来刷新输入缓存。
 

2.getchar();

浏览过一些文章,单独使用一行getchar();可以避免单个字符造成的错误,但当输入多个字符时,多出的字符仍会造成多余的循环。

 3.通过循环使getchar()读取多次非法字符,直到清除。

while(a!=1&&a!=2)
	{
		printf("Invalid Number!\n");
		printf("Enter the number:");
        while (getchar() != '\n');
		scanf("%d",&a);	
	}

可以解决多个非法字符输出的问题。

4.实现fflush(stdin);

既然fflush(stdin)为未定义行为,我们可以自己编写代码简单实现此函数。

char b;          
do                    
{                     
scanf("%c",&b); 
}
while(b !='\n');

这里,使用scanf读取了多余的数据。

char c;
while((c=getchar())!='\n'&& c!=EOF);

这里使用getchar()读取多余数据。

往往一个程序中需要多次使用scanf函数,我们将其单独封装,方便多次调用

此方法也适用于gcc编译器。

void cl(void)
{
	char b;
	do
	{
	scanf("%c",&b);
	}
	while(b !='\n');
}

if(a!=1&&a!=2)
{
printf("Invalid Number!\n");
printf("Enter the Unit of Weight ([1]-lbs, [2]-kg):");
cl();
scanf("%d",&a);
}

注意:几种方法应该代码位置应该写置scanf之前,若放置之后,虽然能清除缓存区,但仍会多循环一次,推测是由回车造成的,没有进行验证。

  • 24
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_全息玫瑰碎片_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值