关于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=;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 ;
}
这个地方最需要注意的是char变量其实在输入时读取的是键盘缓冲区的内容。上面的写法只是一个变通的写法,安全的写法是清空键盘缓冲区的内容。
参见:http://bbs.bccn.net/thread-248420-1-1.html
用 rewind(stdin); 语句可以达到很好的清空键盘缓冲区的作用。不用考虑太多其他因素。这是我在一本名为《软件开发:编程与设计(C语言版)》中所了解到的,作者是USA的David Conger。
以前也了解到其他的清空键盘缓冲区的方法,如:用getchar();fflush(stdin);等。但感觉很麻烦,不好用,也不容易理解。而rewind(stdin)简单好用,而且是一种可移植的方法。
举个例子:
#include <stdio.h> int main()
{
int i;
char aString[]; printf("Please enter some characters:"); /*先向键盘缓冲区里输入无用字符*/ getchar(); rewind(stdin); /*清空键盘缓冲区里的无用字符*/ printf("Please enter 'OK': "); /*输入字符串“OK”*/ for(i=;i<;i++) /*字符串aString接受字符串“OK”*/
{
aString[i]=getchar();
}
aString[i]='\0'; puts(aString); /*输出字符串aString*/ return();
}
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
#include <stdio.h>
int main()
{
char ch1;
char ch2;
ch1 = getchar();
ch2 = getchar();
printf("%d %d", ch1, ch2);
return ;
}
程序的本意很简单,就是从键盘读入两个字符,然后打印出这两个字符的ASCII码值。可是执行程序后会发现出了问题:当从键盘输入一个字 符后,就打印出了结果,根本就没有输入第二个字符程序就结束了。例如用户输入字符’a', 打印结果是97,10。这是为什么呢?
【分析】:
scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读取时遇到回车(n)而 结束的,这个n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符n,这样第二次的读入函数直接从缓冲区中把n取走了,显然读取成功 了,所以不会再从终端读取!其实这里的10恰好是回车符!这就是为什么这个程序只执行了一次输入操作就结束的原因!
【解决办法】:
清空缓冲区的残留数据。
使用 fflush(stdin); 或 rewind(stdin); 均可起到清空键盘缓冲区的作用,这两个函数均包含在stdio.h这个头文件中
修正后的写法:
Sample two
#include <stdio.h>
int main()
{
char ch1;
char ch2;
scanf("%c", &ch1);
printf("ch1 = %d", ch1);
fflush(stdin);
scanf("%c", &ch2);
printf("ch2 = %d", ch2);
return ;
}
上面的实例只适用于Windows系统,在Linux环境下上面两种写法都是不起作用的,所以还要换个函数。
Sample three
#include <stdio.h>
int main()
{
char ch1;
char ch2;
scanf("%c",&ch1);
printf("ch1=%d",ch1);
setbuf(stdin,NULL);
scanf("%c",&ch2);
printf("ch2=%d",ch2);
return ;
}
(资料来源:http://www.ludou.org/c-clear-buffer-area.html)
关于c语言char类型输入输出的一个bug的更多相关文章
- char类型能否存储一个中文字符?为什么
char类型能否存储一个中文字符?为什么 解答:可以.一个char是两个字节,而一个中文也是两个字节.
- c语言 char*类型作为中间变量将许多字符串保存到一个数组的问题
char*是一个字符串指针,如下面的程序value_作为一个中间变量用来在for循环中scanf输入的值的接收者,然后将value_保存到array中,但是一下程序会出现一个问题就是当你跳出这个函数时 ...
- char类型可不可以存储一个汉字
java采用unicode,2个字节(16位)来表示一个字符, 无论是汉字还是数字字母,或其他语言.char 在java中是2个字节.所以可以存储中文 Java八种基本数据类型1)四种整数类型(byt ...
- K&R《C语言》书中的一个Bug
最近在重温K&R的C语言圣经,第二章中的练习题2-2引起了我的注意. 原题是: Write a loop equivalent to the for loop above without us ...
- 关于各种类型数据char、int、double、float 所占空间长度的计算,而char类型让我长姿势了
#include <iostream> int main() { using namespace std; //int A=10; //double B=6; cout << ...
- int类型和char类型的区别
下面三个定义式的区别: int i = 1; char i = 1; char i = '1'; int用来定义整型变量,char用来定义字符型变量,要清楚的知道三个定义式的区别,可以比较它们在内存中 ...
- C语言基础(6)-char类型
1. char常量.变量 使用单引号‘’引起来的就是char的常量 ‘a’是一个char类型的常量 “a”是一个字符串类型的常量 1是一个int型的常量 ‘1’是一个char型的常量 char a; ...
- C语言基础学习基本数据类型-Char类型
char类型 char类型用于储存字母和标点之类的字符.但是在技术实现上char却是整数类型.为了处理字符,计算机使用一种数字编码,用特定的整数表示特定的字符.字符变量输入输出用%c符号.定义语法如下 ...
- 如何用一个语句判断一个整数是不是二的整数次幂——从一道简单的面试题浅谈C语言的类型提升(type promotion)
最近招聘季,看JULY大哥的面试100题时,碰到这么一个扩展问题: 如何用一个语句判断一个整数是不是二的整数次幂?(此题在编程之美也有) easy, 2的整数次幂的二进制形式只有一个1,只要用i和i- ...
随机推荐
- 监听Android CTS测试项解决方案(一)
前言: 首先这里需要详细叙述一下标题中"监听Android CTS测试项解决方案"的需求.这里的需求是指我们需要精确的监听到当前CTS测试正在测试的测试项. 因为我们知道CTS认证 ...
- linux常用命令:2权限管理命令
权限管理命令 1.权限管理命令:chmod 命令名:chmod 命令英文原意:change the permissions mode of a file 命令所在路径:/bin/chmod 执行权限: ...
- iOS:音频
ios中有很多支持音频的控件,如:播放本地音乐(file URL)的AVAudioPlayer和AudioToolbox.Framework.可以播放音乐库音乐的MPMusicPlayerContro ...
- XMLParser解析xml--内容源自网络(在静态库中不能用GDATA来解析,因为静态库不能加动态库)
</Books> 从其文档结构我们可以看出,要定义一个Book实体类描述具体的书籍信息,其中用于存储的相关xml文档元素的实例变量与对应元素同名(本例:title.author.summa ...
- 第一个Shader的更新,增加爆光度, 属性改为数值型(更直观,精确)
Shader "Castle/ColorMix" { Properties { // 基本贴图 _MainTex ("Texture Image", 2D) = ...
- 在Runbook中添加Checkpoint-workflow
本文说明的是使用Checkpoint-workflow的一种场景(当然还有其他场景需要Checkpoint-workflow). 起因:Windows Azure对Automation账户中的Runb ...
- UDP 打洞 原理解释
终于找到了一份满意的UDP打洞原理解释,附上正文,自己整理了一下源码 3.3. UDP hole punching UDP打洞技术 The third technique, and the one o ...
- jquery 下了框
//选中特定值 $("#Select_GBType").attr("value", "选中项ID"); //获取选中项的值 $(" ...
- ZMMR103-数据批量导入
************************************************************************ Title : ZMMR103 ** Applicat ...
- Codeforces Round #368 (Div. 2)A B C 水 图 数学
A. Brain's Photos time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...