When a user enters multiple keystrokes the meny prints multiple times. It should spit out an error and reprint the menu once...what gives?

void mainMenu(char entries[], int index[])
{
    char choice;
    cout << "Please choose 1, 2, or 3.\n";
    cout << "1. Save a new password\n";
    cout << "2. Display all passwords\n";
    cout << "3. Exit\n\n";
    cout << "Choose 1, 2, or 3: ";
    cin.get(choice);

    while(choice != '1' && choice != '2' && choice != '3')
    {
        cout << "** Invalid Entry **\n";
        cout << "Please choose 1, 2, or 3.\n";
        cout << "1. Save a new password\n";
        cout << "2. Display all passwords\n";
        cout << "3. Exit\n\n";
        cout << "Choose 1, 2, or 3: ";
        cin.get(choice);
    }

    switch(choice)
    {
        case '1': newEntry(entries, index);
        break;
        case '2': display();
        break;
        case '3': exit();
        break;
        default: cout << "\nInvalid Entry\n";
    }
}

Dani AI

Generated

The behavior is caused by leftover characters in the input buffer. As noted, the first read removes the visible character (for example the '4') but leaves the newline (and any extra keystrokes) in the stream, so the next read immediately consumes those and makes the menu appear again.

Two simple, reliable fixes:

  • Read a whole line and use the first non-whitespace character. This consumes the trailing newline and avoids repeated prints (the approach shown by ).
  • If you want to keep reading a single char, explicitly discard the rest of the line after the read. For example:
char choice;
std::cin.get(choice);
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

See std::getline documentation and istream::ignore documentation for details.

A few practical tips tied to the thread:

  • ’s suggestion to factor the menu into a function is good: print once from a single place and call it from the loop.
  • Validate input after consuming the whole line (handle empty lines and EOF). If the stream is in a bad state, use std::cin.clear() before continuing.
  • Be careful with your exit call: std::exit (from <cstdlib>) takes an int; prefer returning from main or calling std::exit(0) unless you have a user-defined exit() function.

Following one of these patterns will make the menu reprint only once per actual user input and avoid the “extra prints” you’re seeing.

Recommended Answers

All 5 Replies

Why not just use cin >> choice?
And while you 're at it, put lines 4 to 8 in a function and reuse it in your while statement.

After the first cin.get(), with an input of 4<enter> you have 4<newline> in the input stream. You get the 4 out of it, but the newline is still there. Since the stream isn't empty your program won't wait for input on the second cin, and read newline instead.

This demo of a menu -> choice pattern is simple and easily adapted to many student type menu -> choice problems.

Note how it simply avoids the very common ...

beginning student problem

of 'dangling char's left in the cin stream' :

// showMenuTakeInChoice.cpp //

#include <iostream>
#include <string>
// #include <cctype> //re. tolower


const std::string MENU =
    "1. Save a new password\n"
    "2. Display all passwords\n"
    "3. Exit\n\n"
    "Choose 1, 2, or 3: ";

char takeInChr( const std::string& msg )
{
    std::cout << msg << std::flush;
    std::string reply;
    getline( std::cin, reply );
    if( reply.size() )
        return reply[0];
    // else ...
    return 0;
}

/*
bool more()
{
    if( tolower( takeInChr( "\nMore (y/n) ? " )) == 'n' )
        return false;
    // else ...
    return true;
}
*/


int main()
{
    char choice;
    bool quit = false;
    while( !quit )
    {
        switch( (choice = takeInChr( MENU )) )
        {
            case '1':
                std::cout << "\n'1' is under construction"
                          << " ...\n\n";
            break;
            case '2':
                std::cout << "\n'2' is under construction "
                          << " ...\n\n";
            break;
            case '3':
                quit = true;
                takeInChr( "\nPress 'Enter' to "
                           "continue/EXIT ..." );
            break;
            default:
                std::cout << "\n'" << choice
                          << "' is NOT a valid choice "
                          << "here ...\n\n";
        }
    }
}

This demo of a menu -> choice pattern is simple and easily adapted to many student type menu -> choice type problems.

Note how it simply avoids the very common ...

beginning student problem

of 'dangling char's left in the cin stream' :

// showMenuTakeInChoice.cpp //

#include <iostream>
#include <string>


const std::string MENU =
    "1. Save a new password\n"
    "2. Display all passwords\n"
    "3. Exit\n\n"
    "Choose 1, 2, or 3: ";

char takeInChr( const std::string& msg )
{
    std::cout << msg << std::flush;
    std::string reply;
    getline( std::cin, reply );
    if( reply.size() )
        return reply[0];
    // else ...
    return 0;
}

/*
bool more()
{
    if( tolower( takeInChr( "\nMore (y/n) ? " )) == 'n' )
        return false;
    // else ...
    return true;
}
*/


int main()
{
    char choice;
    bool quit = false;
    while( !quit )
    {
        switch( (choice = takeInChr( MENU )) )
        {
            case '1':
                std::cout << "\n'1' is under construction"
                          << " ...\n\n";
            break;
            case '2':
                std::cout << "\n'2' is under construction "
                          << " ...\n\n";
            break;
            case '3':
                quit = true;
                takeInChr( "\nPress 'Enter' to "
                           "continue/EXIT ..." );
            break;
            default:
                std::cout << "\n'" << choice
                          << "' is NOT a valid choice "
                          << "here ...\n\n";
        }
    }
}

Thanks guys, great explanation, and suggestions!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.