在学习C++时,经常会遇到一个问题,就是需要混合使用cin>>, cin.getline(), getline()时,有时会碰到不等你输入,就直接运行下一行的情况,如下面代码所示:
// test.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
int main()
{
using namespace std;
cout << "Please input a: ";
int a;
cin >> a;
cout << "a is " << a << endl;
cout << "Please input b: ";
char b[20];
cin.getline(b, 20);
cout << "b is " << b << endl;
cout << "Please input c: ";
string c;
getline(cin, c);
cout << "c is " << c << endl;
system("pause");
return 0;
}
上面这个程序看起来没有任何问题,先输入int类型的a,然后输入char数组b,最后输入string对象c,但是实际运行会是怎样呢?
看下面这个运行结果图就知道了:
还不等你输入b,就会直接将后面的cout语句打印出来,这是为什么呢?
这里其实有很多种情况,首先对于上面这样,先cin>>,再cin.getline()的情况,是因为cin>>会在缓冲区中多出一个回车符,即你输入完之后,敲完回车符之后,cin>>会在缓冲区中再多保留一个回车符,这个多出来的回车符就导致下面cin.getline()执行时,自动读取缓冲区内的回车符,于是这句cin.getline()就相当于你什么都没有敲就执行完了,自然就会去执行下面的语句了。
这种情况的解决方法很简单,在cin>>后面加一句cin.get()就行了,这个cin.get()就会将缓冲区内多出来的回车符消耗掉,于是后面的输入就正常了。
修改后的代码如下所示:
// test.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
int main()
{
using namespace std;
cout << "Please input a: ";
int a;
cin >> a;
cin.get();
cout << "a is " << a << endl;
cout << "Please input b: ";
char b[20];
cin.getline(b, 20);
cout << "b is " << b << endl;
cout << "Please input c: ";
string c;
getline(cin, c);
cout << "c is " << c << endl;
system("pause");
return 0;
}
其实这里就是多加了一句cin.get()。
再次运行时,就能正常工作了,结果如下图所示:
如果我们将程序改成如下所示:
// test.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
int main()
{
using namespace std;
cout << "Please input b: ";
char b[20];
cin.getline(b, 20);
cout << "b is " << b << endl;
cout << "Please input a: ";
int a;
cin >> a;
cout << "a is " << a << endl;
cout << "Please input c: ";
string c;
getline(cin, c);
cout << "c is " << c << endl;
system("pause");
return 0;
}
运行结果如下所示:
可见cin>>在缓冲区多保留一个回车符的情况,对于后面接cin.getline()函数和getline()函数都会有影响,当然,我们这里在cin>>后面加上cin.get()函数肯定也是可以解决问题的。
但其实这个多余的回车符不消耗掉也可以完成我们的任务,那就是使用cin.ignore()函数,这个函数会将之前的输入都忽略掉,那当然就会把缓冲区内多余的回车符给忽略掉了。
所以将代码修改为:
// test.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
int main()
{
using namespace std;
cout << "Please input b: ";
char b[20];
cin.getline(b, 20);
cout << "b is " << b << endl;
cout << "Please input a: ";
int a;
cin >> a;
cin.ignore();
cout << "a is " << a << endl;
cout << "Please input c: ";
string c;
getline(cin, c);
cout << "c is " << c << endl;
system("pause");
return 0;
}
这样再运行就正常工作了:
对于多次使用cin>>,cin.getline(), getline(),每次使用了cin>>之后,都会在缓冲区中多出来一个回车符,所以每次使用了cin>>之后都需要将多出来的回车符处理掉;
但如果连续两次都是cin>>,就不需要将多出来的回车符去掉了。
效果如下如图所示:
这里我就是简单地连续两次cin>>,因为cin的时候,并不是只要读取到回车符就执行完cin,而是必须要读取到相对应的类型的内容从键盘敲入,才会真正执行完cin,不允许输入为空,所以cin>>在等待键盘敲入时,你哪怕先敲回车符,cin>>语句也不会执行结束。
但是cin.getline()函数和getline()函数不同,它们都是以回车符作为唯一的标准,而且允许输入为空,也就是说直接一个回车符就结束,效果如下所示:
// test.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
int main()
{
using namespace std;
cout << "Please input a: ";
char a;
cin >> a;
cin.ignore();
cout << "a is " << a << endl;
cout << "Please input b: ";
char b[20];
cin.getline(b, 20);
cout << "b is " << b << endl;
cout << "Please input d: ";
int d;
cin >> d;
cin.ignore();
cout << "d is " << d << endl;
cout << "Please input c: ";
string c;
getline(cin, c);
cout << "c is " << c << endl;
system("pause");
return 0;
}
运行结果如下图所示:
可以看到无论是cin.getline(),还是getline(),都是支持输入为空的,直接一个回车符就执行结束了,而cin>>不支持输入为空,必须输入相对应类型的内容,才会执行结束。
而且大家可以自己试试,对于仅仅有cin>>的情况,你在每次cin>>后面加一句cin.get()或者cin.ignore(),都不会影响正常工作。
所以总结下来就是,每次cin>>之后,缓冲区内会多出来一个回车符,这个回车符对cin>>不会有影响,但是对于cin.getline()函数和getline()函数就会产生影响,导致还不等你输入,就直接把输入语句执行语句运行结束了,直接去运行后面的程序了;解决方法就是养成习惯,每次cin>>之后,都加一句“cin.get();"或者“cin.ignore();”,而且这两句也不会影响连续多次cin>>的正常工作。
另外有一次我无意间发现,其实遇到这种问题时,你哪怕把cin>>后面的cin.getline()函数或者getline()函数写两遍都可以正常工作,因为就是为了抵消掉缓冲区中多保留的回车符,只是上述的cin.get()和cin.ignore()这两种方法显得比较正式。总之,不管用什么方法,只要能抵消掉回车符都可以解决问题。
特别提示,在普通语句中可能很容易发现cin>>后面使用了cin.getline()或者getline(),但是在存在循环时就很容易忽略cin>>出现在cin.getline()函数和getline()函数的前面,因为一次循环执行结束之后,多出来的回车符还是会在缓冲区里,还是会对接下来的输入产生影响。