Reputation: 73
In this code the menu will appear twice after a section of a or b is made, how do i prevent that from happening? I suspect that it has something to do with cin.get capturing a space perhaps from the first cout statement. If that's the case then the solution would be something that will consume that space. I know getline works for strings but this is a char data type. Also a quick related question, is there a piece of code that acts like getline(cin << ws, stringName) does for strings but for char data types?
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
void displayMenu();
int main()
{
char cSelection;
string sSelection;
//Create menu
const char OPTION_READING = 'A', OPTION_READINGTWO = 'B', OPTION_ENDING = 'C';
do
{
displayMenu();
cout << "\nPlease choose an option" << endl << endl;
cin.get(cSelection);
//respond to choice
switch (cSelection)
{
case OPTION_READING:
case 'a':
cout << "You picked 1" << endl;
break;
case OPTION_READINGTWO:
case 'b':
cout << "You picked 2" << endl;
break;
case OPTION_ENDING:
case 'c':
cout << "Thank you for using this program!";
return 0;
default:
cout << cSelection << " " << "is an invalid choice";
}
} while (toupper(sSelection[0] != OPTION_ENDING));
}
void displayMenu()
{
cout << "\t \t \t" "Menu" << endl << endl;
cout << "A. Option 1\n";
cout << "B. Option 2\n";
cout << "C. Quit program";
}
Upvotes: 0
Views: 1167
Reputation: 66234
Your additional menu hit is from consumption of a newline char that is still in the input stream. Consume it any number of ways, one of which is shown below. I also took the liberty to fix your while
condition, which was not correctly expressed (you were passing a bool
to toupper
, which was clearly not what you wanted. Likewise I changed the use of sSelection[0]
, which is not initialized in this code to cSelection
. As it was, you would invoke undefined behavior:
#include <iostream>
#include <string>
#include <cctype>
#include <limits>
using namespace std;
void displayMenu();
int main()
{
int cSelection;
string sSelection;
//Create menu
const char OPTION_READING = 'A', OPTION_READINGTWO = 'B', OPTION_ENDING = 'C';
do
{
displayMenu();
cout << "\nPlease choose an option" << endl << endl;
if ((cSelection = cin.get()) == EOF)
break;
// eat newline character
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
//respond to choice
switch (cSelection)
{
case OPTION_READING:
case 'a':
cout << "You picked 1" << endl;
break;
case OPTION_READINGTWO:
case 'b':
cout << "You picked 2" << endl;
break;
case OPTION_ENDING:
case 'c':
cout << "Thank you for using this program!\n";
return 0;
default:
cout << cSelection << " " << "is an invalid choice";
}
} while (std::toupper(static_cast<unsigned char>(cSelection)) != OPTION_ENDING);
}
void displayMenu()
{
cout << "\t \t \t" "Menu" << endl << endl;
cout << "A. Option 1\n";
cout << "B. Option 2\n";
cout << "C. Quit program";
}
How It Works
That cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
may look a little cryptic, but it really isn't that bad. C++11 provides a very nice template class called std::numeric_limits
. Given a numeric type, you can fire a static member function of the class and get the numeric limits (min, max, etc) of the type. There are tons of of specializations of that template for every native language type. I advise following the link I provided and checking out how it works and all that it offers.
In our case we're interested in consuming as many chars as possible until we reach a newline, which will be discarded. We use the ignore()
method from our input stream, std::cin
, to accomplish the skipping. Therefore:
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
effectively says "Skip as many chars as you have to looking for a newline. If you find a newline, skip it, then return. Consume as many as you have to, up to EOF if needed."
It may look a little cryptic, but its not uncommon at all, and quite effective.
Anyway, hope it helps.
Upvotes: 1
Reputation: 217870
with #include <limits>
after
cin.get(cSelection);
you may add:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Upvotes: 1