Cin和getline跳过输入

50

之前我发布了一个有关 cin 跳过输入的问题,我得到的结果是使用 flush 和 istringstream,但现在我尝试了所有可能的解决方案,但它们都不起作用。

这是我的代码:

void createNewCustomer () {
    string name, address;

    cout << "Creating a new customer..." << endl;
    cout << "Enter the customer's name: "; getline(cin, name);
    cout << "Enter the customer's address: "; getline(cin, address);

    Customer c(name, address, 0);
    CustomerDB::addCustomer(c);

    cout << endl;
}

但我仍然得到同样的结果,跳过输入,当它接受输入时,将它们存储在空的name中,而在address中它会取出我在name中写的内容,但只取第二个字母到末尾。

我的代码有什么问题?

我尝试了cin.ignore()、 cin.get() 和 cin.clear(),全部和单独使用都没有起作用。

编辑:

main.cpp 中的 main 方法仅调用 mainMenu()。

void mainMenu () {
    char choice;

    do {
        system("cls");
        mainMenuDisplay();
        cin >> choice;
        system("cls");

        switch (choice) {
            case '1':
                customerMenu();
                break;

            case '2':
                dvdMenu();
                break;

            case '3':
                receiptMenu();
                break;

            case '4':
                outro();
                break;

            default:
                cout << '\a';
        }

        cin.ignore();
        cin.get();
    } while (choice != '4');
}

针对客户示例,我将选择1,这是customerMenu()

void customerMenu () {
    char choice;

    do {
        system("cls");
        manageCustomerMenu();
        cin >> choice;
        system("cls");

        switch (choice) {
            case '1':
                createNewCustomer();
                break;

            case '2':
                deleteCustomer();
                break;

            case '3':
                updateCustomerStatus();
                break;

            case '4':
                viewCustomersList();
                break;

            case '5':
                mainMenu();
                break;

            default:
                cout << '\a';
        }

        cin.ignore();
        cin.get();
    } while (choice != '5');
}

我再次选择1来创建一个新的客户对象,现在它将进入MainFunctions.cpp文件并调用函数createNewCustomer(),这是第一个函数。

void createNewCustomer () {
    string name, address;

    cout << "Creating a new customer..." << endl;
    cout << "Enter the customer's name: "; cin.getline(name,256);
    cout << "Enter the customer's address: "; cin.getline(address,256);

    Customer c(name, address, 0);
    CustomerDB::addCustomer(c);

    cout << endl;
}

2
请提供一个完整可编译的示例。如果难以做到,请至少展示调用此函数的函数。 - Benjamin Lindley
好的,我会编辑问题,包括一些类似于堆栈跟踪和示例屏幕截图的内容。 - hakuna matata
你说过你尝试了cin.ignore。给我代码看看,它应该可以工作的。 - J-16 SDiZ
4个回答

91
如果在 cin >> something 后使用 getline,需要在两者之间清除缓冲区中的换行符。
如果不需要读取换行符后的任何字符,我个人最喜欢使用 cin.sync()。然而,这是实现定义的,所以它可能与我的方式不同。对于可靠的方法,请使用 cin.ignore()。或者,如果需要删除前导空格,可以使用 std::ws
int a;

cin >> a;
cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n'); 
//discard characters until newline is found

//my method: cin.sync(); //discard unread characters

string s;
getline (cin, s); //newline is gone, so this executes

//other method: getline(cin >> ws, s); //remove all leading whitespace

4
sync()并非旨在执行该操作,尽管在某些情况下可能有效。但对我来说无效。 - Benjamin Lindley
1
@aizen92,每当你使用cin >> something时,它都会在缓冲区中留下一个换行符。只要你仍在使用cin,当你切换函数时,缓冲区就会保留。如果下一个与cin相关的操作是getline,它将读取剩余的换行符并似乎跳过获取输入。 - chris
2
这是C++11标准的最后一份草案n3242, §27.9.1.5/19 -- "int sync() 作用:如果存在写入区域,调用filebuf::overflow将字符写入文件。如果存在读取区域,则效果由实现定义。". - Benjamin Lindley
5
如果用户在一行中输入超过80个字符怎么办?建议使用:std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); - Robᵩ
1
谢谢,我已经为此苦苦挣扎了相当长的时间。 - Saheb
显示剩余15条评论

18
您的菜单代码结构存在问题:
cin >> choice;   // new line character is left in the stream

 switch ( ... ) {
     // We enter the handlers, '\n' still in the stream
 }

cin.ignore();   // Put this right after cin >> choice, before you go on
                // getting input with getline.

这对我非常有效。 - Patrick Mutwiri

2

我遇到了这个问题,并通过使用getchar()捕获('\n')新字符来解决它。


2

在这里,cin留下的'\n'会产生问题。

do {
    system("cls");
    manageCustomerMenu();
    cin >> choice;               #This cin is leaving a trailing \n
    system("cls");

    switch (choice) {
        case '1':
            createNewCustomer();
            break;

\ncreateNewCustomer()的下一个getline中被消耗了。你应该使用getline-。

do {
    system("cls");
    manageCustomerMenu();
    getline(cin, choice)               
    system("cls");

    switch (choice) {
        case '1':
            createNewCustomer();
            break;

我认为这将解决问题。


要使用 getline,您需要将 choice 更改为字符串,然后它不能像在 switch 中那样使用:您可以使用 choice[0],但这会隐藏错误(例如,“11”将被视为1,但对于忽略行的其余部分的接受错误也是如此)。 - Tony Delroy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接