C++cin详解及清空输入缓冲区

输入原理

程序的输入都有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin对象直接从输入缓冲区中取数据。正因为cin对象是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin对象会直接取得这些残留数据而不会请求键盘输入

一. cin>>

该操作符是根据后面变量的类型读取数据

输入结束条件 :遇到Enter、Space、Tab键。

对结束符的处理 :详见下面注意(2)

注意: 

(1)cin>>等价于cin.operator>>(),即调用成员函数operator>>()进行读取数据。 
(2)当cin>>从缓冲区中读取数据时,若缓冲区中第一个字符是空格、tab或换行这些分隔符时,cin>>会将其忽略并清除,继续读取下一个字符,若缓冲区为空,则继续等待。但是如果读取成功,字符后面的分隔符是残留在缓冲区的,cin>>不做处理。 

(3)不想略过空白字符,那就使用 noskipws 流控制。比如cin>>noskipws>>input;

#include <string> 
#include <iostream>
using namespace std;

int main()
{
    char a;
    int b;
    float c;
    string str;
    cin>>a>>b>>c>>str;
    cout<<a<<" "<<b<<" "<<c<<" "<<str<<endl;

    string test;
    getline(cin,test);//不阻塞
    cout<<"test:"<<test<<endl;
    system("pause");
    return 0;
}
从键盘输入:[回车][回车][回车]a[回车]5[回车]2.33[回车]hello[回车],输出结果是: 

从结果可以看出,cin>>对缓冲区中的第一个换行符视而不见,采取的措施是忽略清除,继续阻塞等待缓冲区有效数据的到来。但是,getline()读取数据时,并非像cin>>那样忽略第一个换行符,getline()发现cin的缓冲区中有一个残留的换行符,不阻塞请求键盘输入,直接读取,送入目标字符串后,再将换行符替换为空字符’\0’,因此程序中的test为空串

二.cin.get

读取字符的情况

输入结束条件:Enter键

对结束符处理:不丢弃缓冲区中的Enter

若要读取单个字符,直接cin.get(char ch)或ch=cin.get()即可

cin.get()的返回值是int类型,成功:读取字符的ASCII码值,遇到文件结束符时,返回EOF,即-1,Windows下标准输入输入文件结束符为Ctrl+z,Linux为Ctrl+d。

cin.get(char var)如果成功返回的是cin对象,因此可以支持链式操作,如cin.get(b).get(c)。

#include <iostream>
using namespace std;

int main()
{
    char a;
    char b;
    a=cin.get();
    cin.get(b);
    cout<<a<<b<<endl;
    system("pause");
    return 0;
}
输入:e[回车],输出: 


注意: 
(1)从结果可以看出,cin.get()从输入缓冲区读取单个字符时不忽略分隔符(空白符),直接将其读取,就出现了如上情况,将换行符读入变量b,输出时打印两次。

(2)cin.get()的返回值是int类型,成功:读取字符的ASCII码值,遇到文件结束符时,返回EOF,即-1,Windows下标准输入输入文件结束符为Ctrl+z,Linux为Ctrl+d。

cin.get(char var)如果成功返回的是cin对象,因此可以支持链式操作,如cin.get(b).get(c)。


读取一行的情况:(会在读取的字符串后面自动加上'\0'

istream& get ( char* s, streamsize n, char delim )

cin.get(数组名,长度,结束符)

其中结束符为可选参数,读入的字符个数最多为(长度-1)个,结束符规定结束字符串读取的字符,默认为ENTER

读取一行可以使用istream& get ( char* s, streamsize n )或者istream& get ( char* s, size_t n, streamsize delim )。二者的区别是前者默认以换行符结束,后者可指定结束符。n表示目标空间的大小

输入结束条件:默认Enter键(因此可接受空格,Tab键),可在第三个参数上自定义结束符

对结束符处理:不丢弃缓冲区中的Enter自定义结束符时同样不丢弃缓冲区中的结束符

#include<iostream>
using namespace std;
int main(void){
  char ch='a',a[20];
  cin.get(a,5);
  cin.get(ch);
  cout<<a<<"--"<<(int)ch<<endl;
return 0;
}

输入:1[空格]23[回车],输出: 


遇到换行符时结束读取,但是不对换行符进行处理,换行符仍然残留在输入缓冲区。第二次由cin.get()将换行符读入变量ch,打印输入换行符的ASCII码值为10。

三.cin.getline(会在读取的字符串后面自动加上'\0'

getline()的原型istream& getline( char * s, streamsize count , char delim);
cin.getline(数组名,长度,结束符) 大体与 cin.get(数组名,长度,结束符)类似

另外,getline()的原型是 istream& getline ( istream &is , string &str , char delim );
因此可采用string test; getline(cin,test);输入字符串
其中 istream &is 表示一个输入流,譬如cin;
string&str表示把从输入流读入的字符串存放在这个字符串中(可以自己随便命名,str什么的都可以);
char delim表示遇到这个字符停止读入,在不设置的情况下系统默认该字符为'\n',也就是回车换行符(遇到回车停止读入)。

区别:

1.cin.get()当输入的字符串超过规定长度时,不会引起cin函数的错误,后面的cin操作会继续执行,只是直接从缓冲区中取数据。

但是cin.getline()当输入超过规定长度时,会引起cin函数的错误,后面的cin操作将不再执行。

当输入的字符数大于count时,则get函数只读取count-1个字符,而其余的字符仍然保存在缓冲区中,还可再对其进行读取;
但是函数getline则不然,getline()会设置失效位(faibit),并且关闭后面的输入,这个时候再 用ch=cin.get()是读取不到留在输入队列中的字符的。
可以用下面的命 令来恢复输入:
cin.clear(); //因为clear()会重置失效位,打开输入。这个时候ch=cin.get();就可以读取留在输入队列中的字符。

2.cin.get读取一行时,遇到换行符(自定义结束符)时结束读取,但是不对换行符(自定义结束符)进行处理,换行符(自定义结束符)仍然残留在输入缓冲区。

getline读取一行字符时,默认遇到’\n’(自定义结束符)时终止,并且将’\n’(自定义结束符)直接从输入缓冲区中删除掉,不会影响下面的输入处理。

两者都会在读取的字符串后面自动加上'\0'

3.cin.get(str,size);读取一行时,只能将字符串读入C风格的字符串中,即char*,但是C++的getline函数还可以将字符串读入C++风格的字符串中,即string类型。string test; getline(cin,test);

鉴于getline较cin.get()的优点,建议使用getline进行行的读取。

输入缓冲区清除方法

通常大家会用sync()函数来清除输入缓冲区的内容。个人感觉还是用ignore更好。

cin.clear()是用来更改cin的状态标示符的,cin在接收到错误的输入的时候,会设置状态位good。如果good位不为1,则cin不接受输入,直接跳过。如果下次输入前状态位没有改变那么即使清除了缓冲区数据流也无法输入。所以清除缓冲区之前必须要cin.clear()。

  sync()的作用就是清除输入缓冲区。成功时返回0,失败时badbit会置位,函数返回-1. 
  另外,对于绑定了输出的输入流,调用sync(),还会刷新输出缓冲区。 

  但由于程序运行时并不总是知道外部输入的进度,很难控制是不是全部清除输入缓冲区的内容。通常我们有可能只是希望放弃输入缓冲区中的一部分,而不是全部。

  比如清除掉当前行、或者清除掉行尾的换行符等等。但要是缓冲区中已经有了下一行的内容,这部分可能是我们想保留的。这个时候最好不要用sync()。可以考虑用ignore函数代替。 

   cin.ignore(numeric_limits<std::streamsize>::max(),’\n’);//清除输入缓冲区的当前行 
   cin.ignore(numeric_limits<std::streamsize>::max()); //清除输入缓冲区里所有内容 
   cin.ignore()//清除一个字符

       可采用cin.get(str,5).get();//清除后面的换行符       


  不要被长长的名字吓倒,numeric_limits<std::streamsize>::max()不过是climits头文件定义的流使用的最大值,你也可以用一个足够大的整数代替它。 


  • 110
    点赞
  • 385
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值