posts - 195,  comments - 30,  trackbacks - 0

今天看完一篇牛人博文,受益匪浅,小记一下。原文更详细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的错误处理

程序执行时有一个标志变量来标志输入的异常状态,其中有三位标志位分别用来标志三种异常信息,他们分别是:failbiteofbitbadbit。这三个标志位在标志变量中是这样分配的:

____________________________________

|     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 阅读(1666) 评论(0)  编辑 收藏 引用 所属分类: 格式.输入输出.数据类型

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

常用链接

留言簿(3)

随笔分类

随笔档案

文章分类

文章档案

友情链接

搜索

  •  

最新评论

阅读排行榜

评论排行榜