cin >> x失败后必须立即检查cin.eof():若为真则是eof结束,否则为格式错误等可恢复失败;getline必须用while(getline(cin,s))判断,不可依赖s.empty()或cin.eof()。

cin >> x 失败后必须立刻检查 cin.eof(),不能只看 cin.fail()
直接写 while (!cin.fail()) 或 if (cin.fail()) 判断失败类型,大概率会把格式错误(比如输“abc”却要读 int)当成 EOF,导致逻辑错乱。
cin.fail() 为 true 时,可能是:
- 遇到 EOF(真正结束)
- 类型不匹配(如
cin >> x中x是int,但输入了"hello") - 流被关闭或底层出错(极少见,但
cin.bad()也会同时为true)
cin.fail() 无法区分。正确顺序是:先尝试读取,再根据返回值分支判断:
int x;<br>if (cin >> x) {<br> // 成功,x 有效<br>} else if (cin.eof()) {<br> // 真正的输入结束(Ctrl+D / Ctrl+Z / 文件尾)<br>} else {<br> // 格式错误或其他可恢复失败,需 <code>cin.clear()</code> + <code>cin.ignore()</code><br>}
用 std::getline() 时,必须用函数返回值判断,别碰 s.empty() 或 cin.eof()
std::getline(cin, s) 的返回值才是流状态——它返回 cin 本身,所以能用于布尔上下文;而 s.empty() 只表示读到了空行,不是结束;cin.eof() 在没触发读取前永远是 false,单独用它会漏掉最后一次有效读取后的 EOF。
典型错误写法:
while (cin.good()) {<br> getline(cin, s); // 最后一次读取失败后仍会进循环一次<br>}正确写法只有这一种:string s;<br>while (getline(cin, s)) {<br> // s 包含完整一行(不含 '\n'),包括空行<br> // 循环退出时,已确认是 EOF 或其他失败<br>}
cin.peek() == EOF 是“试探”,但有副作用,慎用
cin.peek() 不提取字符,只看下一个字符是什么,所以有人想用它预判 EOF。但它有两个坑:
- 如果流已经处于
failbit(比如上次读取失败未清理),peek()可能直接返回EOF,即使后面还有数据 - 调用
peek()可能触发缓冲区刷新,在某些重定向或管道场景下引发意外行为
除非你明确需要“不消费字符地探查”,否则优先用读取动作 + 后续状态检查。例如读整数:
int x;<br>if (cin >> x) { /* ok */ }<br>else if (cin.peek() == EOF) { /* 确实没东西了 */ }<br>else { /* 其他错误 */ }但注意:这里 peek() 必须在 cin.fail() 为 true 后调用,且最好先 cin.clear()。真正健壮的输入循环,要处理三种失败并分别响应
一个生产级的输入循环不能只考虑 EOF,还要应对用户手滑输错、粘贴异常、甚至终端断连等情况。核心是分清三类状态:
-
cin.eof()→ 输入源耗尽,可安全退出 -
cin.fail() && !cin.eof()→ 输入内容不合法,应提示重试,并用cin.clear()清标志、cin.ignore(numeric_limits<streamsize>::max(), '\n')</streamsize>清缓冲区 -
cin.bad()→ 底层 I/O 错误(如 stdin 被关闭),通常不可恢复,应记录日志并终止
最容易被忽略的是:即使你只写 while (cin >> x),一旦用户输入非数字,循环就永久卡住——因为错误数据还留在缓冲区里,下次 >> 会立刻失败,形成死循环。这比“分不清 EOF 和错误”更常导致程序假死。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











