细节:使用scanf函数输入数据时的注意事项,若使用不当会导致程序进入死循环。

1.背景

正常情况下,使用如下的scanf语句就可以向变量a循环输入一个十六进制的值。但是这种scanf的用法有问题吗?答案是有的。问题就在于输入一个非十六进制数的字符就会导致scanf获取值失败,程序进入死循环。

while(1)
{
	int a;
	scanf("%x",&a);
	printf("%#x",a);
}
2.错误示例

错误示例的代码如下所示:

#include <stdio.h>

int main() {
	int a=10;
	while (1) {
		scanf("%x", &a);
		printf("%#x\n", a);
		system("pause");
	}
	return 0;
}

如下所示,当程序执行后,不输入十六进制数,而输入“mmm”。这时发现程序会一直执行,而scanf就好像每次都会自动跳过一样,不再等待用户的输入了。在这里插入图片描述
那么出现这种错误的原因是什么呢?首先看看对scanf的正确使用方式。

3.正确示例

如下代码演示了使用scanf进行数据输入时的正确用法。中间加入了一些打印信息,用于辅助理解输入缓冲区中的情况。

#include <stdio.h>

int main() {
	int a=10;
	int ret = 0;
	char c = 'a';
	printf("第一次输入:"); 
	ret=scanf("%x", &a);
	while (ret!=1) {
		while ((c=getchar()) != '\n')
		{
			printf("缓冲区中的数据:%c\n", c);
		}
		printf("再次输入:");
		ret=scanf("%x", &a);
	}
	printf("%#x\n", a);
	system("pause");
	return 0;
}

运行上面的代码,再次输入"mmm“等非十六进制字符时的现象如下:
在这里插入图片描述
可以看到,当输入“mmm”之后,scanf的返回值并非期望的1(实际是0,表示scanf操作失败,因为输入的数据不是十六进制数)。然后程序往下一个循环中,这个循环中调用了getchar(),为了展示当前输入缓冲区中的数据,使用一个字符获取了getchar()获取到的数据。可以看到,当scanf获取失败之后,其实输入缓冲区中的数据还是没有被取走,还是“mmm”。所以,这就解释了为啥错误示例中的scanf会一直执行失败,就好像直接跳过一样,原因就是输入缓冲区中的数据一直保持的“mmm”,导致scanf也一直返回错误。

4.总结

如果以后需要使用scanf进行循环输入数据,最好向正确代码中一样,使用一个循环用getchar()先把输入缓冲区的数据全部取走(直到获取到’\n’),这样就能确保获取到的是期望的数据。代码框架如下:

#include <stdio.h>

int main() {
	int a=10;
	int ret = 0;
	printf("请输入:");
	ret=scanf("%x", &a);
	while (ret!=1) {
		while (getchar() != '\n')
		{
		}
		printf("请再次输入:");
		ret=scanf("%x", &a);
	}
	printf("%#x\n", a);
	system("pause");
	return 0;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

weekman93

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

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

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

打赏作者

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

抵扣说明:

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

余额充值