在获得有效输入之前正确安全地阅读比您想象的要复杂得多。如果输入无效,例如字母,则流将设置为“失败”状态,并拒绝读取更多字符,直到您清除该状态。但是即使你清除了状态,那个输入仍然在那里等待,顺便说一句。所以你必须忽略这些字符。最简单的做法是在下一个回车键之前忽略所有内容,然后再次尝试输入。
但它变得更加复杂,因为如果流有错误,它会被设置为“坏”状态,或者如果它到达流的末尾,它会被设置为“eof”状态。这两个都不可恢复,因此您必须检测它们并退出程序以避免无限循环。更令人恼火的是,istreams 有一个功能.fail()
,但它会检查它是否在fail
or bad
中,这在我看来几乎没用。所以我写了一点invalid_input
来检查流是否可以继续。
请注意,如果输入超出范围,则手动 get_grade
设置标志。fail
#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;
}
正如您在此处看到的,当给出超出范围的数字、文件结尾、流失败或无效字符时,这不会进入无限循环。