原始题目
以下代码的输出是什么?
int a;
cin >> a;
string s;
getline(cin, s);
cout << "[" << s << "]";
输入:
42
hello
- A.
[hello] - B.
[] - C.
[ hello] - D.
[42]
答案:B(
[])
为什么不是 A:>> 会留下一个换行符
这是 cin >> 和 getline 混用的经典陷阱。
关键在缓冲区里残留的内容:
cin >> a读到42后就停了——它读到数字结尾就认为读取完成,换行符\n仍然留在输入缓冲区里:
缓冲区: "42\nhello\n"
↑↑ ↑↑↑↑↑↑↑↑↑
读走 残留:"\nhello\n"
getline(cin, s)从当前位置开始读,第一个字符就是那个残留的\n——它认为“这一行已经结束了”,于是读到一个空字符串就返回。真正的
hello还在缓冲区里,根本没被读到。
所以输出是 [ + 空串 + ],即 [],选 B。
选项 C
[ hello]是干扰项——如果残留的是一个空格才会这样,但>>跳过前导空白,留下的必然是\n。
缓冲区逐步演示
| 步骤 | 操作 | 缓冲区剩余 | 变量值 |
|---|---|---|---|
| 1 | cin >> a |
"\nhello\n" |
a = 42 |
| 2 | getline(cin, s) |
"hello\n" |
s = "" ← 吃掉了空行 |
| 3 | cout << "[" << s << "]" |
— | 输出 [] |
正确写法:先把残留的换行符吃掉
int a;
cin >> a;
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // 跳过到行尾
string s;
getline(cin, s);
cout << "[" << s << "]"; // 输出 [hello]
需要 #include <limits>。简化写法(不考虑行内多余字符):
cin.ignore(); // 默认丢弃 1 个字符,够吃掉一个 '\n'
什么时候可以混用
| 写法 | 混用 getline 安全吗 |
|---|---|
cin >> n 之后 getline |
❌ 留下 \n,读到空行 |
cin >> s(读单词)之后 getline |
❌ 同样留下 \n |
getline 之后 getline |
✅ 完全安全,逐行读 |
cin.ignore() 清理之后再 getline |
✅ 安全 |
考点总结(CSP-J 初赛选择题)
cin >>不消耗换行符,它读完目标数据就停,\n留在缓冲区。getline遇到\n就结束,读到空串也照样返回。- 二者混用必须先
cin.ignore()(或cin.get())清掉残留换行。 - 秒杀技巧:题目里
cin >>后紧跟getline,优先怀疑输出是空串/缺一行,选项里找[]这类“空内容”答案。
思考题
把 cin >> a 改成 cin >> a >> ws;(ws 操纵符),再 getline,输出是什么?
答案
[hello]。ws(whitespace 操纵符)会连续跳过缓冲区中的所有空白字符(包括 \n),相当于轻量版的 ignore,之后的 getline 就能正常读到 hello。



