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

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

Related

Validating Input C++ [duplicate]

This question already has answers here:
How to test whether stringstream operator>> has parsed a bad type and skip it
(5 answers)
Closed last year.
int num = 0;
while(true){
cout << "enter num: ";
cin >> num;
if(!(num)){
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "num must be an int" << endl;
}else if(num <= 0){
cout << "num must be greater than 0" << endl;
}else if(static_cast<double>(static_cast<int>(num)) != num){
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "num must be an int" << endl;
}else{
break;
};
};
I've been looking through SO and I found some threads that addressed similar issues, but nothing that is specific to what I'm trying to achieve. I'm only trying to accept integer inputs, no decimals, no strings, no characters. If I enter in a negative number or 0, it'll throw me an error saying "num must be greater than 0." If I enter in a, it'll throw me an error saying "num must be an int." If I enter 1.0, it'll throw me an error saying "num must be an int."
The problems I'm running into with this is when I enter in 0 for example, instead of executing the conditional statement that checks (num <= 0), it runs the conditional statement that says (!(num)). The other problem I'm running into is when I enter in a value that has a decimal, like 2.0, it'll truncate the numbers after the decimal and send in 2 as the value, completely glossing over the check to see if it's a decimal value and telling the program that it's a valid integer when it's not.
Does anyone have a solution for this, or an article link that solves problem like mines? Thank you!
This:
cin >> num;
if(!(num))
Should be this:
if (!(cin >> num))
You are checking the value of num when you should instead be checking the error state of cin. operator>> returns a reference to the input stream, which is then implicitly convertible to bool, where false means the stream encountered an error.
Also, this is completely useless:
else if(static_cast<double>(static_cast<int>(num)) != num)
Casting an int value to an int is a no-op, and casting an int value to a double back to an int will get you the original int value.
num is an int, it can't read in anything else. So, by the time your code reaches this point, you know num must be holding a valid int value. However, if the user had actually entered a floating-point number instead, operator>> would have stopped reading at the decimal point, leaving it and the remaining fractional value in cin's input buffer for later reading.
Also, the 2nd call to cin.ignore() is wrong. By that point, operator>> was able to read in an int value, it just wasn't satisfactory to you. So don't ignore subsequent input yet.
If you really need to differentiate between integer and floating-point input, you will have to read in the input as a string first, and then parse it to see what it actually holds, eg:
int num = 0;
string s;
size_t pos;
while (true){
cout << "enter num: ";
if (!(cin >> s)){
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "input error, try again" << endl;
}
else{
try{
num = stoi(s, &pos);
if (pos != s.size()) throw invalid_argument("");
if (num > 0){
break;
}
cout << "num must be greater than 0" << endl;
}
catch (const exception &){
cout << "num must be an int" << endl;
}
}
}
Online Demo

Why does this cause in infinite loop with chars but not doubles?

I feel like im doing something really silly wrong. I just want the program to tell the user when they are entering non-doubles, and continue to loop back to the cin where you enter a value.
I want the user to input any number. Then essential do this trivial math and repeat. Its working fine in that regard, the problem comes when some unexpected input like a char gets entered. Then the input somehow sends it into a loop where it loops the math problem, instead of just telling the user that they must type a number and looping back to cin type in a new number.
#include <iostream>
#include <cstdlib>
using std::cout; using std::cin; using std::endl;
long double domath(long double i)
{
cout << i << "/" << 2 << "=" << i/2 << endl;
cout << i/2 << "*" << 10 << "=" << (i/2)*10 << endl << endl;
cout << 5 << "*" << i << "=" << 5*i << "\n\n";
return 0;
}
int main()
{
long double in = 0;
while(true)
{
cin >> in;
if (cin.fail()) {
in = char(int(in));
}
domath(in);
}
system("pause>nul");
return 0;
}
You don't clear the cin in case of fail, and it infinitely tries to parse wrong input to double, failing every time. You need to clear the buffer in case of error:
if (cin.fail()) {
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
in = char(int(in));
}
Also, can't understand what you're trying to achieve with
in = char(int(in));
in is a long double variable and will hold the last value you assigned to it, no need to "convert" it to do math.
Couldn't you try doing something like this?
int x;
if(std::cin >> x)
doSomethingCool(x);
else
std::cout << "Error, not a valid integer!" << std::endl;
Exit your loop on bad input.
I think this just feels more natural/looks cleaner than clearing the buffer and all the other jazz. Just my opinion.
if (cin >> x) - Why can you use that condition?
edit: Bul's answer is still a good one though.

C++ Infinite Loop causing a stack overflow error?

Okay, so I've been working on my calculator. I am currently trying to get it to tell the difference between a valid integer and a character. As an easy workaround I did:
int calc()
{
cout << "Number 1:"; cin >> fnum;
cout << "Number 2:"; cin >> snum;
if (snum <= -1000 || fnum <= -1000)
{
cout << ("Error: Invalid Number!") << endl;
calc();
}
else
{
ff();
}
return 0;
}
And whenever I enter in a character it goes into an infinite loop saying:
SymbolHere:Number 1:Number 2:
ff(); is calling in the calculation function.
I was wondering how to fix this and prevent a stack overflow/ infinite loop? Pastebin Link: http://pastebin.com/GxN2uJAQ
EDIT: ok, there are a number of things with this code.
wait = 0;
while (wait <= 5)
{
wait++;
}
will do absolutely nothing, your program will increment so fast this is undetectable to the human mind. I would recommend removing this entirely.
if (snum >= 0 || fnum >= 0)
{
cout << ("Error: Invalid Number!") << endl;
wait = 0;
while (wait <= 5)
{
wait++;
}
system("CLS");
calc();
}
why are you sending an error message if these numbers are valid? Unless you are only adding negative numbers, this should have a different range.
your function calls also never resolve back into main, instead they call each other (ff and calc) infinity, the program honestly has too many flaws and bad programming practices. Drop whichever tutorial/book you have and try finding a more up to date list(sorry for being harsh, but it has to be said).
C++ Primer Plus
CPlusPlus.com
TheNewBoston(Recommended)
You probably have an input fail by entering say a char for an int, you need to make sure to catch anything thrown by cin and clear the state:
std::string err = "error!";
try {
std::cin >> x;
if(!cin)
throw err;
//....
}
catch(std::string& ee)
{
std::cout << ee << std::endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
}
make sure to include <limits> in your file.

How do I prevent a runaway input loop when I request a number but the user enters a non-number?

I need to know how to make my cin statement not appear to 'remove' itself if you input the wrong type. The code is here:
int mathOperator()
{
using namespace std;
int Input;
do
{
cout << "Choose: ";
el();
cout << "1) Addition";
el();
cout << "2) Subtraction";
el();
cout << "3) Multiplication";
el();
cout << "4) Division";
el();
el();
cin >> Input;
}
while (Input != 1 && Input != 2 && Input!=3 && Input!=4);
return Input;
}
Execute, enter, for example, a character, and it loops nonstop acting as though the cin statement isn't there.
You must check that input succeeded and handle when it doesn't:
int mathOperator() {
using namespace std;
int Input;
do {
cout << "Choose: ";
el();
cout << "1) Addition";
el();
cout << "2) Subtraction";
el();
cout << "3) Multiplication";
el();
cout << "4) Division";
el();
el();
while (!(cin >> Input)) { // failed to extract
if (cin.eof()) { // testing eof() *after* failure detected
throw std::runtime_error("unexpected EOF on stdin");
}
cin.clear(); // clear stream state
cin.ignore(INT_MAX, '\n'); // ignore rest of line
cout << "Input error. Try again!\n";
}
} while (Input != 1 && Input != 2 && Input!=3 && Input!=4);
return Input;
}
If you don't check that extraction succeeded, then cin is left in a failed state (cin.fail()). Once in a failed state, later extractions will immediately return instead of trying to read from the stream, effectively making them no-ops – leading to your infinite loop.
Unless you're quite certain about the input being in the proper format, you rarely want to use operator>> directly from the input stream.
It's usually easier to read a line with std::getline, put that into a std::istringstream, and read from there. If that fails, you print/log an error message, throw away the remainder of the line and (possibly) go on to the next line.
After reading in a bad value, cin is in a "failed" state. You have to reset this.
You must both clear the error flag and empty the buffer. thus:
cin.clear();
cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
The second call "flushes" the input buffer of any data that might be there, to get you ready for the next "cin" call.
If you find yourself writing these 2 lines "all over your code" you could write a simple inline function to replace it.
inline void reset( std::istream & is )
{
is.clear();
is.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
}
Although I have made this function take any istream, most of the time it would only be used for cin where a user is entering and enters something invalid. If it's an invalid file or stringstream input, there is no way to fix it and you would do best to just throw an exception.
don't read int, read char so cin will pass any invalid character
char Input;
do
{
// same code
}
while (Input != '1' && Input != '2' && Input != '3' && Input!='4');
return Input;
[EDIT]
If you want convert char to int you can use this piece of code
int i = (Input - 48);
I agree that a char is just as handy, since you can always cast to int, to answer your question as to why this is happening, when a cin input is exected as an int but a char is entered, the input is kept in the input stream for the duration of the loop, which is why it seems to "disappear."
For more information: see the post from Narue at http://www.daniweb.com/forums/thread11505.html

While loop with try catch fails at bad cin input

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*.