Correctly and safely reading until you get valid input is far trickier than you'd think. If there's invalid input, like a letter, the stream is set in a "failure" state, and refuses to read any more characters until you clear the state. But even if you clear the state, that input is still waiting there, in the way. So you have to ignore those characters. The easiest thing to do is simply ignore everything until the next enter key, and then try the input again.
But it gets even more complicated, because if the stream has an error, it gets set in a "bad" state, or if it reaches the end of the stream, it gets set in a "eof" state. Neither of these two are recoverable, so you must detect them and quit the program to avoid an infinite loop. Even more irritating, istreams have a .fail()
function, but that checks if it's in fail
or bad
, which makes it nearly useless in my opinion. So I wrote a little invalid_input
which checks if the stream can continue.
Note that get_grade
sets the fail
flag manually if the input is out-of-range.
#include <iostream>
#include <stdlib.h>
#include <limits>
bool invalid_input(std::istream& in)
{return in.rdstate() == std::ios::failbit;}
std::istream& get_single_grade(std::istream& in, int& grade) {
std::cout << "Please enter a grade value between 0 and 100." << "\n";
if (in>>grade && (grade<0 || grade>100))
in.setstate(std::ios::failbit);
return in;
}
bool get_grade(std::istream& in, int &grade) {
while(invalid_input(get_single_grade(in, grade))) { //while we failed to get data
in.clear(); //clear the failure flag
//ignore the line that the user entered, try to read the next line instead
in.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}
return in.good();
}
int main(int argc, char* argv[]) {
int grade = -1; // grade will hold grade value; initialized to -1
if (get_grade(std::cin, grade) == false) {
std::cerr << "unxpected EOF or stream error!\n";
return false;
}
std::cout << grade << "\n";
return EXIT_SUCCESS;
}
As you can see here, this doesn't get into an infinite loop when given out of bounds numbers, end of file, a stream failure, or invalid characters.