While loop with try catch fails at bad cin input - c++

I can't seem to figure out why this falls into a loop after getting non-int input. I've tried cin.flush(), which doesn't seem to exist, cin.clear(), which seems like it should work, even cin.sync() after reading someone else post about it working, but didn't seem to make much sense. Also tried cin.bad().
Thank you very much for any help
Please enter the first number: f
Sorry, I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?
Please enter the first number: Sorry,
I don't think that's a number?Sorry,
you d on't get any more tries. Press
any key to continue . . .
#include <iostream>
using namespace std;
int main(){
int entry;
int attempts = 1;
int result;
while(attempts <= 5) {
try {
cout << "\n\nPlease enter the first number: ";
cin >> entry;
if (cin.fail())
throw "Sorry, I don't think that's a number?";
if (entry < 0)
throw "Sorry, no negative numbers. Try something else? ";
cout << "\nNow the second number: ";
cin >> entry;
cin.clear();
cin.get();
}
catch (char* error) {
cout << error;
attempts++;
}
}
if (attempts > 5)
cout << "Sorry, you don\'t get any more tries.\n";
system("pause");
return 0;
}

You should think carefully what you want to do if user gives invalid input in this case. Usually in these cases the best solution is to read one line from the input and throw it away.
Try putting cin.clear() and std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n'); in your catch clause. cin.clear() clears the failure state in cin, and cin.ignore() throws away rest of the line waiting in the input buffer.
(And yes, you probably should rethink your use of exceptions).

The most straight-forward (but not usually the easiest nor the fastest) way of dealing with validation of line-based input is to always read it line at a time. This way no extra whitespace (such as linefeed characters) is left unread in the buffer in any case, and discarding erroneous input is also quite automatic.
// Infinite loop for retrying until successful
while (true) {
// Ask the user something
std::cout << prompt;
// Read the answer (one full line)
std::string line;
if (!std::getline(std::cin, line))
throw std::runtime_error("End of input while expecting a value");
// Put the line read into iss for further parsing
std::istringstream iss(line);
int val;
// Read val from iss and verify that reading was successful and
// that all input was consumed
if (iss >> val && iss.get() == EOF) return val;
std::cout << "Invalid input, try again!\n";
}
It is fun to make a BASIC style input function out of this:
template <typename Val> void input(std::string const& prompt, Val& val) {
// (the above code goes here, slightly adjusted)
}
int main() {
int w;
double l;
input("Enter weight in kg: ", w);
input("Enter length in m: ", l);
std::cout << "BMI: " << w / (l * l) << std::endl;
}
Notes for the pedantics who were going to downvote me:
function input should be specialized for std::string
exceptions thrown by the input function should be caught in main

My Problem was to block char input to a cin >> number
This error caused an 'infinite' loop showing my prompt cout << prompt
with no way of exit but kill the process ...
The following shows what worked for me!
========================================
double fi_trap_d() // function to return a valid range double catching errors
{
double fi_game_sec;
//-------------------------------------------
do
{
fi_game_sec = -1;
cout << fi_game_sec_c;
//------------------------------
cin.ignore(); // (1)
//------------------------------
try
{ cin >> fi_game_sec; cin.clear(); } // (2)
catch (...) //out_of_range)
{
fi_game_sec = -1;
cout << " Dis am an error!\n";
// just loop back as we asked for a number
}
} while (fi_game_sec < 1);
//-------------------------------------------
return fi_game_sec;
}
========================================
Despite trying the " Dis am an error! " has NEVER shown up.
The key was (1) & (2) !

Exceptions should be used to handle exceptional, unexpected situations. Incorrect input from a user is neither unexpected nor exceptional -- it's more or less the norm. Personally, I tend to just ignore most bad input completely (when it can't be prevented). When (and only when) they enter something unusable repeatedly is it even worth pointing it out to them. As such, I'd tend to write the code something like:
char ch;
int attempts = 0;
std::cout << "Please enter the first number: ";
do {
cin >> ch;
attempts++;
if (attempts > 5)
std::cerr << "The only allowable inputs are '0' through '9'\n";
} while (cin.good() && !isdigit(ch));
int first_number = ch - '0';
This reads the input as a character, so it's always removed from the input stream. Then it attempts to validate the input, and if it fails, attempts to read again. Of course, you might want/need to get a little more elaborate, such as reading an entire line, attempting to convert it to a number, and reading another line if that fails.

Why are you doing this with exceptions? You're not going to kill the program on input, so you shouldn't throw an exception.
Just print out your error message and attempt to read in again.

It looks like you would be better off with iostream's native exceptions. Enable with
cin.exceptions( ios::failbit );
try {
…
} catch( ios_base::failure & ) {
cin.clear();
…
}
Never, ever throw an an object not derived from std::exception, and especially not a native type like char*.

Related

std::cin failure leading to looped if statement in while loop

So I figure I'll put this here since I had to traverse a lot of docs and forums to find the definitive answer. I was trying to get input from the user and check if the input was an integer using isdigit() in an if statement. If the if statement failed the program would output an error message. Although, when a nondigit character was entered the program would loop through the error message endlessly. Here's that code:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if(isdigit(guess))
{
game.guess(guess);
else
{
std::cout << "Error\n"; //this would be looped endlessly
}
}
std::cout << "You got " << game.getCorrect() << " correct" << std::endl;
return 0;
}
NOTE: Solved, only posted to include my solution. Feel free to correct if I stated anything incorrectly.
The posted way will fail sometimes and will cast the doubles to integers if any doubles are input.
Use something like the following
int getIntInput() {
try {
std::string input;
std::cout << "\nPlease Enter a valid Integer:\t";
std::cin >> input;
size_t takenChars;
int num = std::stoi(input, &takenChars);
if (takenChars == input.size()) return num;
} catch (...) {}
return getIntInput();
}
Problem: The program kept hold of the non-integer value stored in the cin buffer. This leads to the program never leaving the error message.
Solution:
Use std::cin.fail() to check if the input matches the variable data type. I.E. int was the expected input but the user entered a char. In this case std::cin.fail() would be true.
In the case of std::cin.fail(), use std::cin.clear() and std::cin.ignore(std::numeric_limits<int>::max(), 'n') std::cin.clear() will clear the error flag. The std::cin.ignore(std::numeric_limits<int>::max(), 'n') will ignore any other input that is not an integer and will skip to the new line. Effectively progressing the program.
The solution implemented in my code looks like this:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if (std::cin.fail())
{
std::cout << "Please enter a valid number\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
}
game.guess(guess);
}
Hope this helps and that it saves some people the tedious research because of never learning std::cin error handling! Note: I'm aware my implementation skips the current move, call it punishment ;)

C++ : check whether an input is a number

I want the user to enter a key and I want to check whether the key is a number or not, throw a message if it is not and exit if it is 0.
I read an answer that suggested the below method here : isdigit() c++, probably simple question, but stuck
int key;
while (true){
cout << "Enter Key (Press 0 to Exit) : ";
if (cin>>key){
if (key == 0){ break; }
//Code goes here
}
else{cout<<"Key should be a digit "<<endl;}
}
but my code goes into an infinite loop as soon as I enter an alphabet and I am not able to figure out why.
Any help would be appreciated or if there is a better alternate method for the same then do suggest.
cin>>key
try to read an int from the console.
If you enter a non number character the next read from cin will set the cin stream into error state and nothing can be read from cin anymore until you clear the error flags of the stream.
cin.clear();
resets the error state.
You also have to ignore the entered chars which results in failure mode with
cin.ignore();
Example:
int main()
{
int i;
while (1)
{
std::cin >> i;
if ( std::cin.fail())
{
std::cout << "Something went wrong with cin" << std::endl;
std::cin.clear();
std::cin.ignore();
}
else
{
std::cout << "input works, read: " << i << std::endl;
}
}
}
If you try to read a single digit form console look also here:
Capture characters from standard input without waiting for enter to be pressed
my code goes into an infinite loop as soon as I enter an alphabet
That's because you declared key as an int, so when std::cin fails to read an integer number the stream is set into an error state and the break statement inside the if's is no longer reachable.
A possible alternative is to read a line from the input stream as a string and then try to convert it to a number.
Now, given OP's question:
I want the user to enter a key and I want to check whether the key is
a number or not, ...
It's not clear to me (my fault, probably) if key has to be considered a single or a multi digit number. In the following snippet I'll show the latter case. Please, note that it may include the former too.
#include <iostream>
#include <string>
int main()
{
std::string line;
while ( std::getline(std::cin, line) )
{
if ( line.empty() ) continue;
try
{
int key = stoi(line);
if ( !key ) break;
// code that uses the key...
}
catch ( const std::invalid_argument &e )
{
std::cout << "Key should be a digit!\n";
}
catch ( const std::out_of_range &e )
{
std::cout << "The value entered can't be represented by an int.\n";
}
}
return 0;
}

C++ input failure: multiple inputs in a single statement

My C++ professor is adamant that when checking for input failure, one must use separate while() loops for each individual input. He indicated that the following method of checking more than one input gathered in a single cin statement would not work:
while (!good){
cout << "Enter the length and the width of the rectangle: ";
cin >> length >> width;
if(!cin){
cout << "Bad input, try again" << endl;
cin.clear();
cin.ignore(200, '\n');}
else {
good = true;}}
His proposed method:
bool good = false;
while (!good){
cout << "Enter the length rectangle: ";
cin >> length;
if(!cin){
cout << "Bad input, try again" << endl;
cin.clear();
cin.ignore(200, '\n');}
else {
good = true;}}
while (good){
cout << "Enter the width rectangle: ";
cin >> width;
if(!cin){
cout << "Bad input, try again" << endl;
cin.clear();
cin.ignore(200, '\n');}
else {
good = false;}}
My method above seems to work just fine. If non-numerical characters are inputted for either of the inputs, the loop will prompt for new input and clear the fail-state.
Is it simply considered bad form to check for input failure as I have done? I'm hoping to learn more clearly why my method is erroneous. If my method is faulty, is there a way to check for input failure without using separate loops for every single user-input? I mainly ask because I'm writing a program that involves getting many inputs from a file, and individually checking each variable seems overly tedious. I'm thinking there must be a better way.
Both are "correct" in that they recover from failed inputs and give the user another chance.
Both are only useful for interactive input. You mention reading from a file -- there's really no recovery possible. Ignoring a mangled field will simply cause the next field to be consumed and interpreted differently from what its location in the file indicates. Best course of action when reading from a file is to output as good an explanation as possible (exactly where in the file the error occurred, e.g. line and columns numbers, what kind of data was expected, and what about the data encountered was invalid).
In interactive usage, clearing the buffer and prompting again is useful.. Your version has the disadvantage that after entering a length correctly, if the user fat-fingers the width, they can't just re-enter the wrong data, but have to type the length a second time as well.
Writing the loop a second time is incredibly pointless, however. Instead you should write a helper function, something like:
template<typename T>
T prompt_for_value( const char* const prompt )
{
T result;
while (true) {
std::cout << prompt << std::flush;
if (std::cin >> result) return result;
std::cout << "Bad input, try again" << std::endl;
}
}
double width = prompt_for_value<double>("Enter the width in meters: ");
double height = prompt_for_value<double>("Enter the height: ");
Notice that the code is shorter overall and avoids the clunky use of the good variable which inverted its meaning halfway through the original code. Also, the call site now is very clean and focuses completely on the important information -- the prompt and the data type of the input.
Thanks the C++11 lambda support, it's now also very easy to add parameter validation to the helper function:
T prompt_for_value( const char* const prompt, std::function<bool(T)> validation = {} )
{
T result;
while (true) {
std::cout << prompt << std::flush;
if (std::cin >> result) {
if (validation && !validation(result)) {
std::cout << "Input out of range, try again" << std::endl;
continue;
}
return result;
}
std::cout << "Bad input, try again" << std::endl;
}
}
double width = prompt_for_value<double>("Enter the width in meters: ",
[](int w) { return w >= 0; });
double height = prompt_for_value<double>("Enter the height: ",
[&width](int h) { return (h >= 0) && (h <= 10000.0 / width); }));
What you have indicated as your professor's proposed method is very bad form as given due to violation of the don't-repeat-yourself (DRY) principle in the code. If you want to do basically the same thing multiple times, you should either use a loop or a function to avoid writing duplicate logic.
Your method involves all-or-nothing checking and therefore may require the user to repeat themselves. The usability of this should be decided on a case-by-case basis.
Both methods fail to detect extraneous characters at the end of the input line. Such input might reasonably be interpreted as erroneous -- regardless of whether or not it happens to work with the subsequent input request.
However, as you have demonstrated, the all-or-nothing approach does in fact basically work. Given that, here's an alternative all-or-nothing implementation based on the automatic exception-based checking that the iostream library is capable of.
cin.exceptions( ~std::ios::goodbit );
int length=0, width=0;
for ( bool ok=false; !ok; )
{
try
{
cout << "Enter the length and the width of the rectangle: ";
cin >> std::skipws >> length >> width;
std::string s;
std::getline( cin, s );
s.erase( std::remove_if( s.begin(), s.end(), ::isspace ), s.end() );
if ( !s.empty() ) throw std::runtime_error("too much input");
ok = true;
}
catch( std::ios::failure const & e )
{
cout<<"\n"<<"bad input ["<<e.what()<<"], try again...\n";
cin.clear();
cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
}
catch( std::runtime_error const & e )
{
cout<<"\n"<<e.what()<<", try again...\n";
}
}
cout<<"\n"<<"length="<<length<<", width="<<width<<"\n";
Output:
Enter the length and the width of the rectangle: x
bad input [basic_ios::clear], try again...
Enter the length and the width of the rectangle: 1 x
bad input [basic_ios::clear], try again...
Enter the length and the width of the rectangle: 1 2 x
too much input, try again...
Enter the length and the width of the rectangle: 1 2 3
too much input, try again...
Enter the length and the width of the rectangle: 4 5
length=4, width=5

Read Integer from User

I am trying to read an integer from terminal. Here's my code:
int readNumber()
{
int x;
std::cin >> x;
while(std::cin.fail())
{
std::cin.clear();
std::cin.ignore();
std::cout << "Bad entry. Enter a NUMBER: ";
std::cin >> x;
}
return x;
}
Whenever I run this code I get:
Type in the number for the newsgroup that shall be deleted:
joöä
Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: Bad entry. Enter a NUMBER: 8
Why does it write "bad entry" multiple times?
If I remove std::cin.clear(); or std::cin.ignore();, the program just keeps writing
Enter a NUMBER: Bad entry. Can anyone explain why it does that?
This is actually a partial duplicate of an old question, but it is phrased differently enough that I will address it briefly here.
You get infinite printing without those two lines, because cin.clear() is required to clear the error flag that cin.fail() is reading. See the linked question for details.
Why does it still print more than once when those lines are there? When you do std::cin >> x;, your code will read the first character in your input, and attempt to parse it as an int. It will fail, and then in the next iteration of the loop, it will attempt to parse the next character and fail again. For each failure (that is, each character in your input), it will print Bad entry. Enter a NUMBER:. If you type some bad input with fewer characters, you will see what I mean.
There are multiple ways to fix this problem, but one simple fix is to read the entire input into a string, and try to parse it, instead of using cin directly into an int. Here is some sample code which needs to be compiled with one of the various compiler-dependent flags for C++11. I have tested it with your input and it appears to achieve the effect you desire.
#include <iostream>
#include <string>
#include <stdexcept>
bool tryParse(std::string& input, int& output) {
try{
output = std::stoi(input);
} catch (std::invalid_argument) {
return false;
}
return true;
}
int main(){
std::string input;
int x;
getline(std::cin, input);
while (!tryParse(input, x))
{
std::cout << "Bad entry. Enter a NUMBER: ";
getline(std::cin, input);
}
return x;
}
Try this anyway... As I type this directly into stackoverflow might have compilation error
int readNumber()
{
int x=0;
while(true)
{
std::cin >> x;
if(!std::cin.fail()){
break;
}
else{
std::cout << "Bad entry. Enter a NUMBER: " << std::endl;
std::cin.clear();
std::cin.ignore( std::numeric_limits<streamsize>::max(), '\n' );
}
}
}
int main() {
char* input;
std::cin >> input;
int x = std::atoi(input);
while(x == 0 && strcmp(input, "0") != 0) {
std::cout << "Bad entry. Enter a NUMBER: ";
std::cin >> input;
x = std::atoi(input);
}
return x;
}
Notice that when you have 3 non-int chars, it will repeat 3 times, when you have 5, it's repeated 5 times.
It's because cin is tries the first char, fails, try the second char, fails and so on until all your input chars are parsed.
cin.fail() returns true if the last cin command failed, and false otherwise.
Try this instead:
while(1)
{
std::cin >> x;
if (!std::cin.fail()) break;
std::cin.clear();
std::cin.ignore(10000,'\n');
std::cout << "Bad entry. Enter a NUMBER: ";
}

Requiring valid input with cout/cin

I have a game where the user needs to enter x and y coordinates within a certain range, one at a time. Right now my input code is as follows:
do {
printf("\n");
cout << "X: ";
cin >> x;
cout << "Y: ";
cin >> y;
} while (cin.fail());
I'm new to c++ but reading documentation lead me to believe this was an acceptable method for verifying user input. It works perfectly when the input is valid, however when the input is of a different type (for instance entering "a") it infinitely loops with "X: Y: ". What do I need to do differently to have it wait for user input as if the lines were being read for the first time?
You should check every single input operation:
std::cout << "X: ";
if (!(std::cin >> x)) { /* error */ }
std::cout << "Y: ";
if (!(std::cin >> y)) { /* error */ }
It's up to you how you want to handle the error. You could return early, break from a loop, throw an exception... it all depends.
Note that you could loop until you get something parseable, but that's dangerous if the user closes the input stream. Better to read line by line and parse:
std::cout << "Please enter an integer X: ";
int x;
bool success = false;
for (std::string line; std::getline(std::cin, line); )
{
std::istringstream iss(line);
if (iss >> x >> std::ws && iss.get() == EOF) // #1
{
success = true;
break;
}
std::cout << "Sorry, please try again: ";
}
if (!success)
{
std::cerr << "Unexpected end of input stream!\n";
std::exit(1);
}
This way, if the user presses [Ctrl]-D in the middle of the session, the program shuts down immediately and doesn't try to read more values from the closed input stream.
The condition on the line marked #1 tests both for a successful parsing of an integer as well as for having reached the end of the line (gobbling intermediate whitespace).
The biggest problem with trying to parse per variable is that when a user makes a mistake, their whole input becomes suspect.
Consider if I skip invalid input and enter: "3e4 40". I meant "34 40", but skipping the e might make "3 4" and leave "40" for later or might leave "4 40".
Consider using getline to read a whole line in and parsing it such as with istringstream just as you are now -- any error becomes an error without leaving the inputstream in a weird state.