浅议C编程中遇到scanf函数的一些问题

 scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的。但是有时候却就是因为使用这些函数除了问题,却找不出其中的原因。下面先看一个很简单的程序:

      char ch1, ch2
	scanf("%c", &ch1); 
	scanf("%c", &ch2);
	printf("%d  %d/n", ch1, ch2);
或者

       char ch1, ch2;
	ch1 = getchar();
	ch2 = getchar();
	printf("%d  %d/n", ch1, ch2);
上述两段程序的意思就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。
当运行时当我们输入a按空格再输入b后程序结束输出97 32不是我们预期的结果(97,98)为什么呢?

讨论:

首先我们看一下输入操作的原理, 程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的:

当一次键盘输入结束时会将输入的数据存入输入缓冲区,而scanf函数(getchar()函数)直接从输入缓冲区中取数据。正因为scanf函数(getchar()函数)是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入,这里我们运行程序时先输入a然后输入空格最后输入b按下回车键后输出运行结果,这里我们依次把字符a,字符空格,字符b,字符回车存入输入缓冲区,而scanf函数(getchar()函数)首先取a(ASCII码97)字符赋给ch1再取输入缓冲区的第二个字符空格ASCII码32赋值给ch2。输出结果就是这样产生的。那么怎样解决这个问题呢?很简单如下:

 	char ch1, ch2,ch;
 	scanf("%c", &ch1); 
 	while((ch=getchar())!='\n')continue;
	scanf("%c", &ch2);
 	printf("%d %d/n", ch1, ch2);
加上语句while((ch=getchar())!='\n')continue; 即可。此时输入a,然后输入空格,按回车,最后输入b,按下回车键后输出运行结果97 98即为a和b的ASCII码。为什么写这条语句就OK了呢?答案:这是根据前面对scanf函数和getchar()函数读取数据的原理的分析而得出来的解决方案。while((ch=getchar())!='\n')continue;这条语句在上述程序中的执行流程是:首先按照上述输入,输入完后此时缓冲区的数据依次为a,空格,回车符,b,回车符。语句scanf("%c", &ch1);读取输入缓冲区的第一个a字符给ch1,然后语句while((ch=getchar())!='\n')continue;中getchar()函数循环的从输入缓冲区中读取a以后的数据,直到读取到第一个回车符('\n')后停止循环。它的作用说白了就是把字符b前面输入的一些垃圾数据全部吸收掉。这样接下来执行scanf("%c", &ch2);语句时因为前面缓冲区中的数据a,空格,回车符,都被一次读过了,接下来就读到字符b,将其赋给ch2。

下面对上面的问题在提供另一种解决方案,代码如下:

	char ch1, ch2;
	scanf("%c", &ch1); 
	scanf(" %c", &ch2); 
	printf("%d %d\n", ch1, ch2);

此处与原问题不同之处是在语句scanf(" %c", &ch2);中在%c前面加了一个空格,然后运行程序,此时先输入a然后空格,回车可以随便输(无论输入多少空格,回车都没事),再输入b,则结果输出a和b的ASCII码值。但是这个地方的原理我没弄懂,不知道为什么在%c前加一个空格这一微小的改变,结果就会有如此的不同,如果有知道为什么的还请不吝赐教!似乎是scanf函数与空白符之间存在一些关系。


解决方案三:

	char ch1, ch2;
	scanf(" %c", &ch1); 
	fflush(stdin);
	scanf("%c", &ch2);
	printf("%d %d\n", ch1, ch2);
使用fflush(stdin);函数fflush清除一个流即在完成第一个参数输入后使用fflush(stdin)清空缓冲数据区,这样就不会影响到第二个输入了。

结论:任何问题都可以从多个不同的角度去解决,不要只局限与一种方法,要多动手,勤思考,只有这样才会有更大的收获。


关于scanf函数的详细介绍大家可以参考这篇博客http://blog.csdn.net/21aspnet/article/details/174326点击打开链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值