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点击打开链接