细节:使用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;
}
©️2020 CSDN 皮肤主题: 成长之路 设计师:Amelia_0503 返回首页