I\'m having a problem with what should be incredibly simple code. I want to take in an integer between 1 and 3 with error checking. It works fine for checking for numbers
The problem is that:
cin >> input;
Will cause the bad bit to be set when you try and read a non numeric value. After that happens any attempt to use the operator>>
is silently ignored.
So the way to correct for this is to test if the stream is in a good state and if not then reset the state flags and try and read again. But note that the bad input (that caused the problem) is still on the input so you need to make sure you throw it away as well.
if (cin >> input)
{
// It worked (input is now in a good state)
}
else
{
// input is in a bad state.
// So first clear the state.
cin.clear();
// Now you must get rid of the bad input.
// Personally I would just ignore the rest of the line
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// now that you have reset the stream you can go back and try and read again.
}
To prevent it getting stuck (which is caused by the bad bit being set) read into a string then use a string stream to parse user input. I also prefer this method (for user interactive input) as it allows for easier combination of different styles of reading (ie combining operator>>
and std::getline()
as you can use these on the stringstream).
#include <iostream>
#include <sstream>
#include <string>
// using namespace std;
// Try to stop using this.
// For anything other than a toy program it becomes a problem.
int main(int argc, char *argv[])
{
int input;
std::string line;
while(std::getline(std::cin, line)) // read a line at a time for parsing.
{
std::stringstream linestream(line);
if (!(linestream >> input))
{
// input was not a number
// Error message and try again
continue;
}
if ((input < 1) || (input > 3))
{
// Error out of range
// Message and try again
continue;
}
char errorTest;
if (linestream >> errorTest)
{
// There was extra stuff on the same line.
// ie sobody typed 2x<enter>
// Error Message;
continue;
}
// it worked perfectly.
// The value is now in input.
// So break out of the loop.
break;
}
}
You declared input as int but when you write an alphanumeric character to input it will try to implicitly convert it into integer. But you error checking does not account for this.
Ur problem can be easily solved by changing your while loop. instead of checking this how about you check
while(input!=1 || input!=2 || input!=3)
Most of these answers include unnecessary complexity.
do{
cout << "\nPlease enter a number from 1 to 3:" << endl;
cout << "-> ";
if(!cin){
cout << "Invalid input"
cin.clear()
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}while(!(cin >> input))
Use numeric_limits<streamsize>::max()
to completely clear the
buffer after a failed cin
.
Use cin.clear()
to reset the fail flag on cin
so !cin
wont
always evaluate false.
cin.fail()
is fine. However some would consider !cin
more natural.
from my previous post https://stackoverflow.com/a/43421325/5890809
#include <iostream>
#include <string>
using namespace std;
int validatedInput(int min = 1, int max = 3)
{
while(true)
{
cout << "Enter a number: ";
string s;
getline(cin,s);
char *endp = 0;
int ret = strtol(s.c_str(),&endp,10);
if(endp!=s.c_str() && !*endp && ret >= min && ret <= max)
return ret;
cout << "Invalid input. Allowed range: " << min << "-" << max <<endl;
}
}
int main(int argc, char *argv[])
{
int val = validatedInput();
cout << "You entered " << val <<endl;
return 0;
}