C++中的cin, cin.getline, getline等混合使用时不能输入直接执行下一行的问题

在学习C++时,经常会遇到一个问题,就是需要混合使用cin>>, cin.getline(), getline()时,有时会碰到不等你输入,就直接运行下一行的情况,如下面代码所示:

// test.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <cstring>
#include <string>


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 <iostream>
#include <cstring>
#include <string>


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 <iostream>
#include <cstring>
#include <string>


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 <iostream>
#include <cstring>
#include <string>


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 <iostream>
#include <cstring>
#include <string>


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()函数的前面,因为一次循环执行结束之后,多出来的回车符还是会在缓冲区里,还是会对接下来的输入产生影响。

猜你喜欢

转载自blog.csdn.net/leowinbow/article/details/82190631