Reputation: 23
Sorry, I'm sure this question gets asked a million times. I've searched, and I've found answers for "Press ENTER to continue", but for the life of me, I can't find the answer to my question.
do{
//something something
cout<<"Press ENTER to continue or anything else to quit."<<endl;
//Enter is pressed or something else
}while(Enter is pressed)
here's what I'm trying to use it for
do{
cout<<"Enter value: ";
cin>>value[n];
cout<<"Enter 'Y' to continue, anything else to quit"<<endl;
cin>>reply;
}while(reply == 'y' || reply == 'Y')
In place of "Enter 'Y' to continue. Anything else to quit." I just want an "Enter to continue, Q to quit".
edit: After implementing what Tony D showed, I now have
do{
cout<<"Enter the person's first name, last name, and age."<<endl;
cin>>list[n].firstName>>list[n].lastName>>list[n].age;
n++;
cout<<"Press ENTER to continue. 'Q' to quit. ";
std::getline(std::cin, reply);
}while (std::getline(std::cin, reply) && reply != "Q" && reply != "q");
it works, but I feel like something is still wrong. If I do just while (std::getline(std::cin, reply) && reply != "Q" && reply != "q");
Q or q won't exit the loop and Enter just takes me to the next line. I tried this as a do while and a while loop.
Upvotes: 2
Views: 4746
Reputation: 106196
Firstly, when you do streaming like this (adding error handling)...
if (!(cin>>list[n].firstName>>list[n].lastName>>list[n].age))
{
std::cerr << "oops... unable to parse `firstname lastname age' from stdin... terminating\n";
return EXIT_FAILURE;
}
...the parsing of input for age
terminates on and does not consume the first whitespace character following. That means the terminating newline will always be left on the cin
stream. So, you need to do something to get rid of it. A simple way to do that while making it clear that you're not interested in the rest of the line's content is:
std::cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
If you prefer to check everything really carefully, you could use std::getline(std::cin, line)
to read the line of input into a std::string
, then construct a std::stringstream
with it, then parse out the content like this:
std::string line;
if (cin>>list[n].firstName>>list[n].lastName>>list[n].age))
{
std::istringstream iss(line);
if (!(iss >> firstName >> lastName >> age))
{
std::cerr << "oops... unable to parse `firstname lastname age' from stdin... terminating\n";
return EXIT_FAILURE;
}
char c;
if (iss >> c) // this should fail - no more non-whitespace content allowed...
{
std::cerr << "oops... extra input encountered after the age value... terminating\n";
return EXIT_FAILURE;
}
}
Once we're sure you're reading the entire line of per-person input, for the loop termination itself it's probably easiest to use:
do
{
...
} while (std::getline(std::cin, my_string) && my_string != "Q" && my_string != "q");
That way, any newline characters will automatically be removed from the stream. Using std::cin.get()
to read a single character from the stream is possible and more efficient, but it's a little trickier handling the newline. Can get fancier if you want to ignore leading whitespace, complain about other non-empty input etc..
Whatever you type may not reach the stream until you press enter, so they'll need to press 'Q' to quit. To avoid that, you'd need OS-specific non-Standard code or libraries. There are plenty of SO questions explaining how to read keys without waiting for enter.
If you need to tolerate errors and prompt the user to try again, the easiest approach is to read in a way that can't fail due to invalid input, then use a separate stream object when you're attempting the parsing that may fail. The following shows how to parse a few variables out of a line of input:
std::string line;
while ((std::cout << "enter x y z (space separated): ") &&
std::getline(std::cin, line))
{
std::istringstream iss(line); // input string stream with contents of last line read
char c;
if ((iss >> x >> y >> z) && !(iss >> c))
// we successfully parsed out x, y and z, and there was no trailing
// non-whitespace character, so all's good...
break;
std::cerr << "unable to parse 'x', 'y' and 'z' from input, or unexpected trailing text\n";
std::cerr << "please try again\n";
}
This way, iss
may enter a bad state due to merely bogus user input but is recreated with the next line's content anyway. std::cin
only fails on unrecoverable issues (end-of-file, hardware error etc). That avoids having to reset any stream state, which is a painful thing to have to do, see http://support.microsoft.com/kb/132422 for an example program showing how.
Upvotes: 3