题目
编写程序,循环从控制台读取合法的正整数。当用户误输入非数字字符(如字符串、符号或越界数字)时,程序不得陷入死循环,而应捕获 cin.fail() 错误标志,使用 cin.clear() 清除错误位,并使用 cin.ignore() 彻底排空输入缓冲区中的脏字符,直到用户成功输入合法的正整数为止。
输入格式:可能包含若干行非法字符,最终以合法正整数结束。
输出格式:对于每次非法输入输出警告提示,成功录入后输出该数字及其校验平方值。
数据范围与约定:目标数字 <code>x ∈ [1, 10^9]</code>。
思路与算法
1. 输入流状态位模型std::cin 内部维护四个状态位:goodbit(正常)、eofbit(文件尾)、failbit(格式不匹配或解析失败)、badbit(底层流致命损毁)。当读入字符与类型不符时,failbit 置位,后续读取全部被静默忽略。
2. 错误恢复两步法
第一步必须执行 std::cin.clear() 重置错误标志,使流恢复可读状态;第二步必须调用 std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'),丢弃导致故障的整行残留残余字符,否则下次 cin >> 仍会读取同一个错误字符导致死循环。
3. 范围越界防御
若输入过大导致整数溢出,failbit 同样会被激活。因此对数据类型选型为 long long 并在业务逻辑上做 val > 0 的合法区间防御。
完整程序
#include <iostream>
#include <limits>
int main() {
long long value = 0;
std::cout << "请输入一个正整数:\n";
while (true) {
if (std::cin >> value) {
// 类型匹配成功,校验正整数约束
if (value > 0) {
break;
}
std::cout << "[防御提示] 输入必须是大于 0 的正整数,请重新输入:\n";
} else {
// 触发 failbit / badbit,流被阻断
std::cin.clear(); // 1. 清除错误标志
// 2. 清空缓冲区中直至换行符的所有无效内容
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "[防御提示] 检测到非法字符或格式错误,已重置输入流,请重新输入数字:\n";
}
}
std::cout << "成功录入合法数值: " << value << "\n";
std::cout << "数值平方: " << value * value << "\n";
return 0;
}运行示例
输入:
abc
-12
42输出:
请输入一个正整数:
[防御提示] 检测到非法字符或格式错误,已重置输入流,请重新输入数字:
[防御提示] 输入必须是大于 0 的正整数,请重新输入:
成功录入合法数值: 42
数值平方: 1764