简体   繁体   中英

Need help fixing strange cin behavior

I'm building a product checkout piece of software and I keep hitting a strange bug. I have a central menu that gets user input. After a function is finished with its task, it sends the user back to the menu. For certain functions, however, the cin.get() I have after the menu prompt bugs out and won't accept the first command given. Here are the relevant code fragments:

The main menu loop:

bool foreverLoopFlag = true;
while (foreverLoopFlag) {

    cout << "\nC[heckout], R[eturn], S[tudent], P[roduct], Q[uit]. Choice? ";
    cin.get(actionChoice);
    std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n');
    cout << endl;

    actionChoice = toupper(actionChoice);

    switch (actionChoice) {
        case 'C':
            checkoutSoftware(studentMap, productList);
            break;
        case 'R':
            returnSoftware(studentMap, productList);
            break;
        case 'S':
            studentDisplay(studentMap, productList);
            break;
        case 'P':
            productDisplay(studentMap, productList);
            break;
        case 'Q':
            foreverLoopFlag = false;
            break;
        default:
            cout << "Invalid command.\n";
            break;
    }
}

A problem-child function, studentDisplay:

void studentDisplay(map<string, Student> & studentMap, list<Product> & productList) {
string inputCLID;

cout << "Please enter student CLID: ";
cin >> inputCLID;

if (studentMap.find(inputCLID) != studentMap.end()) {
    cout << "\nStudent: " << studentMap[inputCLID].name << " (" << inputCLID << ")\n";
    cout << "\tBorrowed items: " << endl;
    for (list<Student::LentProduct>::iterator it = studentMap[inputCLID].checkedOut.begin(); 
         it != studentMap[inputCLID].checkedOut.end(); it++) {
        cout << "\t\tProduct: " << (*it).name;
        cout << "\tDue Date: " << (*it).dateDue << endl;
    }


} else {
    cout << "\nError: CLID not in database.\n";
}
}

Some of the indention was mangled moving over to SE, I apologize. Here an example of the issue I'm having:

C[heckout], R[eturn], S[tudent], P[roduct], Q[uit]. Choice? s

Please enter student CLID: mrx8394

Student: Mark Xeno (mrx8394)
    Borrowed items:
        Product: Bluebeard  Due Date: 12/14/2013

C[heckout], R[eturn], S[tudent], P[roduct], Q[uit]. Choice? c

Invalid command.

C[heckout], R[eturn], S[tudent], P[roduct], Q[uit]. Choice? q

I tried putting a std::cin.flush() at the beginning of the menu-loop, but that didn't work. I tried doing std::cin.ignore(std::INT_MAX) at the beginning of the menu-loop, but that makes it to where the menu never even shows up. I also tried a std::cin.sync(), but that just makes an infinite cycle of this:

C[heckout], R[eturn], S[tudent], P[roduct], Q[uit]. Choice?
Please enter a product to checkout:
Error: No such product.

I have no idea where to go from here. I know it is probably just some quirk of the iostream that I'm not picking up on. Any assistant would be appreciated.

EDIT: I do not have enough reputation to upvote or comment on specific answers (all of my rep is on Math.SE!!!), so I'll comment here. @Igor-tandetnik 's solution worked perfectly. I had moved everything else over to a getline, but I suppose that guy just got left in the shuffle. My thanks come in droves.

@qwrrty While it may be folly, I had a specification to meet (don't you just love low level University courses). I don't typically ask for help debugging assignments, but this was the last bug and my knowledge of iostream isn't that deep, but I knew someone on here would know what was bugging out my stream state.

Thanks again guys, cheers!

cin >> inputCLID reads characters up to, but not including, the first whitespace character (in your example, a line feed). That character is left in the stream. It is that character that cin.get(actionChoice) later retrieves.

I tend to think that for interactive input, trying to use stdin and/or cin for reading anything other than a full line of input is folly. There are just too many ways for your program to get confused about what's still on the input stream, and end up in an unrecoverable state.

At the very least I'd modify the program to say what command it thinks is invalid, or product that doesn't exist:

    default:
        cout << "Invalid command '" << actionChoice << "'\n";

and

    cout << "Error: No such product '" << productChoice << "'\n";

That way at least you can get an idea of what input the program is actually using for these variables.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM