关于c语言char类型输入输出的一个bug
题目
输入一个整数n,接下来n行每一行输入两个用一个空格分隔的字符。
对每一对字符,比较其大小关系并输出比较的结果:1、0、-1.
解决的代码如下:
#include<stdio.h> int main() { int N,i; char c1=' ',c2=' '; scanf("%d",&N); getchar(); for(i=0;i<N;i++) { scanf("%c %c",&c1,&c2); getchar(); if(c1>c2) printf("1\n"); else if(c1<c2) printf("-1\n"); else printf("0\n"); } return 0; }
这个地方最需要注意的是char变量其实在输入时读取的是键盘缓冲区的内容。上面的写法只是一个变通的写法,安全的写法是清空键盘缓冲区的内容。
参见:http://bbs.bccn.net/thread-248420-1-1.html
用 rewind(stdin); 语句可以达到很好的清空键盘缓冲区的作用。不用考虑太多其他因素。这是我在一本名为《软件开发:编程与设计(C语言版)》中所了解到的,作者是USA的David Conger。
以前也了解到其他的清空键盘缓冲区的方法,如:用getchar();fflush(stdin);等。但感觉很麻烦,不好用,也不容易理解。而rewind(stdin)简单好用,而且是一种可移植的方法。
举个例子:

1 #include <stdio.h> 2 3 int main() 4 { 5 int i; 6 char aString[3]; 7 8 printf("Please enter some characters:"); /*先向键盘缓冲区里输入无用字符*/ 9 10 getchar(); 11 12 rewind(stdin); /*清空键盘缓冲区里的无用字符*/ 13 14 printf("Please enter 'OK': "); /*输入字符串“OK”*/ 15 16 for(i=0;i<2;i++) /*字符串aString接受字符串“OK”*/ 17 { 18 aString[i]=getchar(); 19 } 20 aString[i]='\0'; 21 22 puts(aString); /*输出字符串aString*/ 23 24 return(0); 25 }
Microsof Visual C++下调试结果:
输入:abcdefghijk回车OK回车
输出:OK
之前缓冲区里的abcdefghijk垃圾字符都被清空了。
下面向新手解释一下rewind(stdin);的工作原理。
C语言把键盘,显示器等设备当做文件来处理,也就是说从键盘输入相当于从一个文件中读入,向显示器输出相当于向一个文件写出。
而stdin是C标准库定义的标准文件之一,它与键盘相关联。我一般把它理解为指向键盘这个“文件”的指针。
而rewind()函数的作用是把文件的当前位置指针指向文件头。
两者结合,rewind(stdin);的作用也就是把“指向键盘(一个文件)的指针从当前位置挪到键盘(一个文件)开头”,相当于抛弃了当前键盘缓冲区中的数据,重新开始输入。
虽然并不是真正的把缓冲区里的数据全部清掉,但却起到了清空键盘缓冲区的作用。
也可参考:http://blog.sina.com.cn/s/blog_63c66eb60100sc0o.html
空键盘缓冲区很多种方法,如用fflush(stdin);
rewind(stdin);
setbuf(stdin, NULL);前两者仅对windows有用,最后一个则对Linux系统也适用。那么为什么需要清空键盘缓冲区呢?
以下几个实例:
Sample one
1 #include <stdio.h> 2 int main() 3 { 4 char ch1; 5 char ch2; 6 ch1 = getchar(); 7 ch2 = getchar(); 8 printf("%d %d", ch1, ch2); 9 return 0; 10 }
程序的本意很简单,就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。可是执行程序后会发现出了问题:当从键盘输入一个字 符后,就打印出了结果,根本就没有输入第二个字符程序就结束了。例如用户输入字符’a', 打印结果是97,10。这是为什么呢?
【分析】:
scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读取时遇到回车(n)而 结束的,这个n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符n,这样第二次的读入函数直接从缓冲区中把n取走了,显然读取成功 了,所以不会再从终端读取!其实这里的10恰好是回车符!这就是为什么这个程序只执行了一次输入操作就结束的原因!
【解决办法】:
清空缓冲区的残留数据。
使用 fflush(stdin); 或 rewind(stdin); 均可起到清空键盘缓冲区的作用,这两个函数均包含在stdio.h这个头文件中
修正后的写法:
Sample two
1 #include <stdio.h> 2 int main() 3 { 4 char ch1; 5 char ch2; 6 scanf("%c", &ch1); 7 printf("ch1 = %d", ch1); 8 fflush(stdin); 9 scanf("%c", &ch2); 10 printf("ch2 = %d", ch2); 11 return 0; 12 }
上面的实例只适用于Windows系统,在Linux环境下上面两种写法都是不起作用的,所以还要换个函数。
Sample three
1 #include <stdio.h> 2 int main() 3 { 4 char ch1; 5 char ch2; 6 scanf("%c",&ch1); 7 printf("ch1=%d",ch1); 8 setbuf(stdin,NULL); 9 scanf("%c",&ch2); 10 printf("ch2=%d",ch2); 11 return 0; 12 }
(资料来源:http://www.ludou.org/c-clear-buffer-area.html)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
2013-11-29 OpenJudge数据结构与算法-计算点的距离并排序
2013-11-29 OpenJudge计算概论-取石子游戏