C++的标准输入

从一个简单的问题谈起

昨天做题的时候,遇到一个输入是这样的

3 4
aaaa aaaa aaaa
bbbbbbb bbbb
ccc cccccccc
^D

第一行输入一个整数n,表示接下来句子的数量,和另外一个整数(这里没有作用,只是用来说明下面的一个情况),接下来就是n个句子,每个句子以回车结束。
我的想法是

int ij;
cin >> i >> j;
while(i--){
 string s;
 getline(cin, s);
}

可是,结果是我第一次调用getline返回的是“”(空字符串)。这是为什么呢?

原因是cin有它的缓冲区,当我们在标准输入输入回车之后,会将我们的输入放到它的缓冲区,然后cin就开始在缓冲区读。 cin的>>操作符,默认是以空格,制表符作为分隔符的。

当我们输入 3 4换行之后,输入缓冲区读到的内容是3 4\n,cin >> 操作符将3 4读取之后赋给i,j,缓冲区里面剩下\n,下一个getline来读的时候就返回空字符串了。

一个解决方法,用cin.get()吸收掉缓冲区的\n字符。

int ij;
cin >> i >> j;
cin.get();
while(i--){
 string s;
 getline(cin, s);
}

其实,我之前一直认为cin >> 操作符是以空格,制表符,回车作为分隔符的,对于代码cin >> i >>j;,我曾经这么输入。

2
3

这样i,j读到的也是2,3,所以我就以为cin >> 也可以以回车作为分隔符。今天我查资料才发现,cin >> j的时候,缓冲区里面是有\n3的,只是它为j赋值的时候忽略掉\n而已。

cin的状态

在找这个问题的原因的时候我发现一个更有意思的事情。

cin.clear()
int a;
char  b;
int ret = 0;
cout << "input a:" << endl;
cin >> a;
cout << "a:" << a << endl;
cout << "input b:" << endl;
cin >> b;
cout << "b:" << b << endl;

这行代码如果输入的不是数字而是字符的话,会导致一个死循环,因为第一次赋值给a的时候,赋值失败了,cin就会给自己设一个状态iostate state = badbit这就会导致cin不能正常工作,cin >> b也不能正常工作了。
下面是我的输入:

➜  stl git:(master) ✗ g++ input.cpp -o input
➜  stl git:(master) ✗ ./input
input a:
asdf
a:0
input b:
b:

这里我给a赋了个字符,然后cin >> b就直接返回了,没有再给机会输入b,也没有办法让b正确赋值。

int a;
char  b;
int ret = 0;
cout << "input a:" << endl;
cin >> a;
cout << "a:" << a << endl;
cin.clear();  //加了这一句
cout << "input b:" << endl;
cin >> b;
cout << "b:" << b << endl;

在cin错误之后,将状态设置回iostate state = goodbit,这样我的b就能从缓冲区读取我之前的输入。我的输入

➜  stl git:(master) ✗ g++ input.cpp -o input
➜  stl git:(master) ✗ ./input
input a:
asdf
a:0
input b:
b:a      
cin.ignore() and cin.sync()

网上有人说这两个语句都是用来清空输入缓冲区,也就是说回到我第一个谈到的问题,我输入数字之后回车,\n存放在输入缓冲区的最开始,那我就可以通过这两个语句来将输入缓冲区清空,然后再读取其他输入。

cin.ignore()是丢弃输入缓冲区的一个字符,istream& ignore (streamsize n = 1, int delim = EOF);,还可以丢弃n个字符,或抛弃到以delim结尾字符。 这是推荐使用的清空缓冲区的方法。

cin.sync()这个的实际功能依赖于具体实现,我在g++中使用这个函数没有作用,后来在下面这篇文章看到原因。
这篇文章讲到了cin.sync()具体功能依赖于实现, VC++将cin.sync()实现为清空现有缓冲区,而g++什么都不做。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值