50

earlier i posted a question about cin skipping input, and I got results to flush, and use istringstream, but now I tried every possible solution but none of them work.

here is my code:

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;
}

but I'm still getting the same thing, skipping input, and when it does take input, it takes them and stores in name empty nothing, and in address it takes what i wrote in name but from the 2nd letter to the end

what is wrong with my code?

I tried the cin.ignore(), cin.get(), and cin.clear() all of them together and alone, none of them worked

EDIT:

main method in main.cpp invokes mainMenu() only

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');
}

i will choose 1 for the customer example, this is 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');
}

I choose 1 again to create a new customer object, which will now go to the MainFunctions.cpp which will invoke the function createNewCustomer() which is the first one.

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;
}
hakuna matata
  • 3,243
  • 13
  • 56
  • 93

4 Answers4

91

If you're using getline after cin >> something, you need to flush the newline out of the buffer in between.

My personal favourite for this if no characters past the newline are needed is cin.sync(). However, it is implementation defined, so it might not work the same way as it does for me. For something solid, use cin.ignore(). Or make use of std::ws to remove leading whitespace if desirable:

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
chris
  • 60,560
  • 13
  • 143
  • 205
  • 4
    `sync()` is not defined to do that, though it may work in some instances. It doesn't work for me. – Benjamin Lindley May 11 '12 at 14:59
  • @BenjaminLindley, it's always worked perfectly for me. Can you find some documentation where it's not supposed to clear out the unread characters? – chris May 11 '12 at 15:00
  • i didnt use cin before the getline in the function `createNewCustomer()`, but it is used in the functions calling `createNewCustomer()` like in `mainMenu()` and `customerMenu()` – hakuna matata May 11 '12 at 15:01
  • 1
    @aizen92, any time you `cin >> something`, it will leave a newline in the buffer. The buffer remains when you switch functions, as long as you're still using `cin`. If the next operation to do with `cin` is `getline`, it will read that leftover newline and seem to skip getting input. – chris May 11 '12 at 15:02
  • I'll get that doc reference for you in a minute. In the meantime, here's something for you to ponder: http://ideone.com/7ICvn – Benjamin Lindley May 11 '12 at 15:04
  • i added the `cin.sync()` after every `cin >> ` i used, and it worked thanks – hakuna matata May 11 '12 at 15:05
  • @BenjaminLindley, I see your point, but seeing as how I use GCC, could that example have something to do with the fact that you enter all input beforehand? That does kind of change the logic of such things. – chris May 11 '12 at 15:11
  • 2
    Here ya go. n3242, the last C++11 draft, §27.9.1.5/19 -- *"int sync() Effects: If a put area exists, calls filebuf::overflow to write the characters to the file. If a get area exists, the effect is implementation-defined."* – Benjamin Lindley May 11 '12 at 15:12
  • @BenjaminLindley, ah there it is. I'll reflect that in my answer. – chris May 11 '12 at 15:13
  • @chris: What OS are you using? – Benjamin Lindley May 11 '12 at 15:15
  • @BenjaminLindley, Windows, works the same on XP as 7. – chris May 11 '12 at 15:15
  • @chris: That explains the difference. I don't think it matters that you're on GCC. I'm guessing, but I'm not sure, that it has something to do with the way Linux treats everything as a file. – Benjamin Lindley May 11 '12 at 15:18
  • @BenjaminLindley, that would make sense. I don't really use Linux too often, so I'm not that familiar with it. – chris May 11 '12 at 15:20
  • 5
    What if the user types more than 80 characters in a line? Prefer: `std::cin.ignore(std::numeric_limits::max(), '\n');` – Robᵩ May 11 '12 at 17:28
  • @Robᵩ, I sort of left the character limit implied in the comment. I haven't read way in-depth into the input buffer either. I do prefer it for the console as it is shorter than `ignore()` and achieves the same effect there. I agree that it isn't a good choice for files, and apparently not for consoles either if the code is being used in more than one place. – chris May 11 '12 at 17:39
  • @Rob: *"if input is from a terminal, .sync() destroys the remainder of the line."* -- This is not the case for me. The results on my machine are exactly as what happens in the example I gave from ideone. That is to say, cin.sync() appears to do absolutely nothing. – Benjamin Lindley May 11 '12 at 19:10
  • @BenjaminLindley - Your experience and further research on my part reveal my prior statement to be hogwash. I'm deleting that comment. FYI: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46624#c1 – Robᵩ May 11 '12 at 19:19
  • @Robᵩ I have always disliked `ignore()` for this reason. Thank you for mentioning `std::numeric_limits::max()` I did not known about it and now using `ignore()` is back on the table for me. – DuncanACoulter Mar 27 '14 at 07:28
  • 1
    Thanks, had been struggling with this for quite sometime. – Saheb Jan 05 '15 at 06:18
  • cin.ignore() worked for me! – mbaros Jan 23 '17 at 13:54
18

The structure of your menu code is the issue:

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.
jrok
  • 54,456
  • 9
  • 109
  • 141
2

Here, the '\n' left by cin, is creating issues.

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

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

This \n is being consumed by next getline in createNewCustomer(). You should use getline instead -

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

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

I think this would resolve the issue.

theharshest
  • 7,767
  • 11
  • 41
  • 51
  • To use `getline` you'd need to change `choice` to string, then it couldn't be used like that in the `switch`: you could use `choice[0]` but that would hide errors (e.g. '11' would get treated as 1, but that's also the case for the accepted error that ignores the rest of the line. – Tony Delroy Sep 15 '15 at 02:50
2

I faced this issue, and resolved this issue using getchar() to catch the ('\n') new char

user2135533
  • 181
  • 1
  • 2
  • 11