前两天写了一个小程序,程序如下:
main()
{
char a;
char b=1 ;
while(b)
{
printf(" please input a char:");
scanf("%c",&a);
if (a==97)
{
b=0;
}
else
{
printf("your char is %d/n",a);
}
}
}
程序中首先提示用户输入一个char,用scanf函数去读取输入的内容并赋值给 char型的变量a,然后判断此char型变量的值,如果是a(注意a的ASCII码是97)则将b置为0,退出循环,否则,则以十进制打印用户输入的内容,然后继续提示用户输入。。。。直到用户输入的是a,则退出。
但经过编译后,运行,发现一个问题。下面是现象:
C:/TC/TC201E/Project>test6
please input a char:10
your char is 49
please input a char:your char is 48
please input a char:your char is 10
please input a char:
解释:首先,我输入了10,程序打印出 your char is 49,然后继续循环让客户输入,但我还没输入,程序又打印出 your char is 48,等样,又打印出your char is 10,然后才等待用户输入。
网上查了查资料,说计算机将用户输入读取到键盘缓冲区内,每次运行scanf("%c",&a) 时,会从键盘缓冲区内读取未读完的数据进行操作,以上面的例子为准,我输入了10,然后敲了回车,键盘缓冲区内会出现三个字符:1、0、回车。那么依次会从键盘缓冲区内读取1、0、回车字符(回车的ASCII码是10),所以导致上面的输出结果。
那么我的疑问就出来了,这个键盘缓冲区是个什么玩意?是在内存还是键盘呢?如何避免键盘缓冲区的问题呢?
这一系列的问题出来后,挨个解决.
在接触到一个新事物时,我的思路是:首先了解他是什么,他有什么用(what )?为什么要用他(why )?我怎么来用他(how )?我什么时候用他(when )。好,按照我的思路,我们进行下去。当然这几项是我从网上及网友口中得到的答案,如果不正确,敬请校正。
首先,what ,键盘缓冲区就是当你按了键以后如果应用程序来不及响应,就先存在缓冲区里,以后应用程序可以来取。
肯定是在内存里,不过不同系统模式下是不一样的。16位实模式下,一般用BIOS的键盘服务,键盘缓冲区在BIOS的数据区里,位于1MB内存的高端。一般是32个字节什么的。Windows和Linux等32位系统,一般有自己的键盘驱动,不再使用BIOS服务。
接着,why ,由于操作系统的机制,我们不得不用到键盘缓冲区,当你一直按着某个键的时候或者程序来不及处理你输入的内容时,会存放到键盘缓冲区中,等CPU的时间轮询到此任务时,继续进行处理。
接着,how ,我们怎么来用他,更准确的说是,我们如何清空键盘缓冲区,避免错误产生。一般用到fflush(stdin); 首先说明的是C语言把所有的外设都会当成一个文件来进行操作,对于键盘,相当于从一个文件写出;对于显示器,相当于从一个文件读取,而stdin是C标准库定义的标准文件之一,它与键盘相关联。我一般把它理解为指向键盘这个“文件”的指针。所以用fflush(stdin)即可清空键盘缓冲区的内容。当然还有其他方法:rewind(stdin); 这两种方法都需要应用头文件stdio.h,目前测试在windows下可行。linux下没试过,明天去公司试试,网上搜下了下,这两种方法在linux不可行,可以用 setbuf(stdin, NULL) 函数。明天测试下。呵呵
最后,when ,很肯定了,当用到scanf的时候需要根据场景清空缓冲区的时候了。呵呵
前两天解决了此问题,今天总结下,呵呵,如果有不对的地方,欢迎各位网友指正。
备注下:rewind(stdin);的作用也就是把“指向键盘(一个文件)的指针从当前位置挪到键盘(一个文件)开头”,相当于抛弃了当前键盘缓冲区中的数据,重新开始输入。虽然并不是真正的把缓冲区里的数据全部清掉,但却起到了清空键盘缓冲区的作用。
-----------------------华丽的分割线-----------------------------------------------------
昨天把键盘缓冲器的问题发到CSDN的坛子里了,大家还是很给力,问题的连接如下:
http://topic.csdn.net/u/20110531/21/f8a5375f-9b00-4f77-9dcb-645234a8841e.html
其中huiguixian 兄弟给出了Linux内存分布的文章 http://blog.csdn.net/huiguixian/archive/2011/05/23/6440279.aspx
以后可能用的到。呵呵,留用了。