今天看完一篇牛人博文,受益匪浅,小记一下。原文更详细http://blog.csdn.net/lewsn2008/archive/2008/04/16/2295790.aspx
首先我们呢看一下输入操作的原理, 程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin等输入输出函数直接从输入缓冲区中取数据。正因为cin等输入输出函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入。
---------------
1,要注意不同的函数是否接受空格符、是否舍弃最后的回车符的问题!
读取字符时:
scanf()以Space空格、Enter、Tab结束一次输入,不会舍弃最后的回车符(即回车符会残留在缓冲区中),(区别读字符串时会清楚)//所以可以用getchar()清除;
getchar()以Enter结束输入,也不会舍弃最后的回车符;
读取字符串时:
scanf()以Space、Enter、Tab结束一次输入,会舍弃最后的回车符(区别读字符时)和所有的空格等等。
gets()以Enter结束输入(空格不结束),接受空格,会舍弃最后的回车符!
第二:为了避免出现上述问题,必须要清空缓冲区的残留数据,可以用以下的方法解决:
方法1:C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了!
这个函数是fflush(stdin)。
方法2:自己取出缓冲区里的残留数据。
scanf("%[^\n]",string);
-------------------------
cin的学问
一. cin<<
该操作符是根据后面变量的类型读取数据。
输入结束条件 :遇到Enter、Space、Tab键。(这个很重要!)
对结束符的处理 :清楚缓冲区中使得输入结束的结束符(Enter、Space、Tab)
(这里有一点问题,
int i;
char c[100];
cin>>i;
cin.getline(str,100);
cout<<str;
如果输入是:12 adjf回车
输出将先是空格然后adjf;
如果输入是:12回车adjf回车
输出将是adjf.
看来cin>>要在连用时,比如cin>>a>>b;或者cin>>a;cin>>b消除空格能力才体现。
)
二.cin.get()
该函数有三种格式:无参,一参数,二参数
即cin.get(), cin.get(char ch), cin.get(array_name, Arsize)
(i)读取字符的情况:
输入结束条件:Enter键(遇空格不结束)
对结束符处理:不丢弃缓冲区中的Enter
cin.get() 与 cin.get(char ch)用于读取字符,他们的使用是相似的,
即:ch=cin.get() 与 cin.get(ch)是等价的。
测试程序:
#include <iostream>
using namespace std;
int main()
{
char c1, c2;
cin.get(c1);
cin.get(c2);
cout<<c1<<" "<<c2<<endl; // 打印两个字符
cout<<(int)c1<<" "<<(int)c2<<endl; // 打印这两个字符的ASCII值
return 0;
}
测试一输入:
a[Enter]
输出:
a
97 10
【分析】会发现只执行了一次从键盘输入,显然第一个字符变量取的'a', 第二个变量取的是Enter(ASCII值为10),这是因为该函数不丢弃上次输入结束时的Enter字符,所以第一次输入结束时缓冲区中残留的是上次输入结束时的Enter字符!
测试二输入:
a b[Enter]
输出:
a
97 32
【分析】显然第一个字符变量取的'a', 第二个变量取的是Space(ASCII值为32)。原因同上,没有丢弃Space字符。
(ii)读取字符串的情况:
cin.get(array_name, Arsize)是用来读取字符串的,可以接受空格字符,遇到Enter结束输入,按照长度(Arsize)读取字符, 会丢弃最后的Enter字符。
(i i i)cin.getline()
cin.getline() 与 cin.get(array_name, Arsize)的读取方式差不多,以Enter结束,可以接受空格字符。按照长度(Arsize)读取字符, 会丢弃最后的Enter字符。
但是这两个函数是有区别的:
cin.get(array_name, Arsize)
当输入的字符串超长时,不会引起cin函数的错误,后面的cin操作会继续执行,只是直接从缓冲区中取数据。但是cin.getline()
当输入超长时,会引起cin函数的错误,后面的cin操作将不再执行。(具体原因将在下一部分"cin的错误处理"中详细介绍)
------------
cin的错误处理
程序执行时有一个标志变量来标志输入的异常状态,其中有三位标志位分别用来标志三种异常信息,他们分别是:failbit,eofbit,badbit。这三个标志位在标志变量中是这样分配的:
____________________________________
| 2 | 1 | 0 |
| failbit | eofbit | badbit |
|___________|__________|___________|
看一下这几个标志位的作用(引用msdn):
badbit, to record a loss of integrity of the stream buffer.
eofbit, to record end-of-file while extracting from a stream.
failbit, to record a failure to extract a valid field from a stream.
In addition, a useful value is goodbit, where no bits are set.
接下来我么看几个ios类的数据定义(引用msdn):
typedef T2 iostate;
static const iostate badbit, eofbit, failbit, goodbit;
这里ios类定义了这四个常量badbit, eofbit, failbit, goodbit,其实这四个标志常量就是取对应标志位的掩码,也即输入的四种异常情况!
以上四个常量对应的取值为:
ios::badbit 001 输入(输出)流出现致命错误,不可挽回
ios::eofbit 010 已经到达文件尾
ios::failbit 100 输入(输出)流出现非致命错误,可挽回
ios::goodbit 000 流状态完全正常, 各异常标志位都为0
如果出现输入错误,则cin不再工作,我们可以用cin.clear()重置标记位。
测试程序:
#include <iostream>
using namespace std;
int main ()
{
char ch, str[20];
cin.getline(str, 5);
cout<<"flag1:"<<cin.good()<<endl; // 查看goodbit状态,即是否有异常
cin.clear(); // 清除错误标志
cout<<"flag1:"<<cin.good()<<endl; // 清除标志后再查看异常状态
cin>>ch;
cout<<"str:"<<str<<endl;
cout<<"ch :"<<ch<<endl;
return 0;
}
测试输入:
12345[Enter]
输出:
flag1:0 // good()返回false说明有异常
flag2:1 // good()返回true说明,clear()已经清除了错误标志
str:1234
ch :5
但是当前一次读取数据出错后,如果缓冲区没有清空的话,重置错误标志还不够!要是能将缓冲区的残留数据清空了就好了哦!下面我们再来看一个很重要的函数!cin.ignore()
这个函数用来丢弃输入缓冲区中的字符,第一参数定义一个数,第二个参数定义一个字符变量。
例:cin.ignore(5, 'a'); 函数将不断从缓冲区中取一个字符丢弃,直到丢弃的字符数达到5或者读取的字符为'a'。
其实该函数最常用的方式是这样的,将第一个参数设的非常大,将第二个参数设为'\n',这样就可以缓冲区中回车符中的所有残留数据,因为一般情况下前面输入残留的数据是没有用的,所以在进行新一次输入操作前将缓冲区中所有数据清空是比较合理。
如:cin.ignore(1024, '\n');
------
posted on 2009-07-21 15:18
luis 阅读(1673)
评论(0) 编辑 收藏 引用 所属分类:
格式.输入输出.数据类型