C++ 如何与控制台交互
C++ 通过 <iostream> 头文件中的流来完成控制台输入输出。用 cout(字符输出)向外输出,用 cin(字符输入)读取用户的输入。它们用到了两个你之前在位移运算中见过的运算符,在这里被赋予了新的用途:
<<是插入运算符,它把数据送入cout。>>是提取运算符,它从cin中取出数据,存入一个变量。
记住方向的一个简单办法:箭头指向的就是数据流动的方向。既然你已经能用字符串保存文本,接下来就让这些文本进出你的程序。
用 cout 打印
cout 把你插入的内容发送到标准输出。一条语句中可以连续使用多个 <<,自由地混合文本、数字和变量。
每个 << 都会追加到同一行,直到你插入一个换行。有两种方式可以换行:'\n' 插入一个换行字符,而 endl 插入换行符并且刷新缓冲区到屏幕。刷新是有实际开销的,所以在一个打印成千上万行的循环中,优先使用 '\n',流会在需要时自行刷新(程序退出时也一定会刷新)。
// Fine for a one-off message:
cout << "Done" << endl;
// In a hot loop, prefer this - no forced flush each iteration:
for (int i = 0; i < 1000000; ++i)
cout << i << '\n';
用 cin 和 >> 读取
cin >> variable 读取一个以空白字符分隔的记号,并将其转换为变量的类型。它会跳过开头的空格或换行符,然后在下一个空白字符处停止。
由于 >> 遇到空白字符就停止,它很适合读取单个数字和单个单词,但读不了一整句话:输入 hello world 时,cin >> word 只会读到 hello,而 world 留在缓冲区中等待下一次读取。
用 getline 读取一整行
要读取一整行(包括所有空格),请使用 getline(cin, line),它会把按下 Enter 之前的全部内容读入一个 std::string。
只要输入中可能包含空格,比如姓名、地址、句子,它就是正确的工具。不过,一旦把 getline 和 >> 混用,就有一个陷阱在等着你。
getline 页面专门介绍了这个函数:自定义分隔符、一直读取到输入结束,以及用 std::ifstream 逐行读取文件。
cin 与 getline 的换行符陷阱
这是 C++ 输入输出中最常见的 bug。执行 cin >> n 时,提取操作读取了数字,却把换行符(你按下的 Enter 键)留在了输入缓冲区中。接下来的 getline 立刻看到这个残留的换行符,认为这一行已经结束,于是返回一个空字符串,根本没有停下来等待输入。
int age;
string city;
cin >> age; // you type 30 and press Enter; '\n' stays in the buffer
getline(cin, city); // reads the leftover '\n' -> city is "" (empty!)
解决方法是在 >> 之后、getline 之前,用 cin.ignore 丢弃这个残留的换行符:
cin.ignore(numeric_limits<streamsize>::max(), '\n') 会一直跳过字符,直到吃掉一个换行符(或到达输入末尾)。这是稳妥的写法:更短的 cin.ignore() 只丢弃一个字符,如果用户在数字后面多输入了空格就会出问题。养成使用完整写法的习惯。
输入失败时
如果用户在需要数字的地方输入了字母,提取操作就会失败:cin 进入错误状态,目标变量保持不变(从 C++11 起会被设为 0)。更糟的是,一旦 cin 处于失败状态,之后的每次读取也都会被静默跳过,你可能因此陷入死循环。
恢复总是分两步:cin.clear() 重置错误标志,让流重新可用;cin.ignore(...) 丢掉仍然卡在缓冲区里的错误字符。如果省略 ignore,错误的输入会一直留在那里,下一次 >> 又会失败,这就是经典的死循环。之所以能直接在条件中判断 cin >> n,是因为流处于失败状态时会转换为 false。
要避免的常见错误
- 用
cin >> s读取一句话。 它会在第一个空格处停止。凡是包含空格的内容都用getline。 - 在
>>和getline之间忘了cin.ignore。 残留的换行符会让你得到一个空行。先清空缓冲区。 - 到处都用
endl。 每个endl都会强制刷新一次。默认使用'\n',只在输出必须立即显示时才用endl。 - 忽视
cin读取失败。 读取数字时输入了字母,cin就会处于失败状态;再次读取之前,一定要先clear()再ignore()。
常见问题
C++ 中为什么用了 cin 之后,getline 会直接跳过输入?
cin >> x 读取了数字,却把你按下的换行符留在了缓冲区里。接下来的 getline 读到这个残留的换行符,立即返回一个空字符串。在 >> 之后、getline 之前,先用 cin.ignore(numeric_limits<streamsize>::max(), '\n'); 清除它。
C++ 中 endl 和 \n 有什么区别?
两者都会结束当前行,但 endl 还会把输出缓冲区刷新到屏幕上,而 '\n' 只插入一个换行符。刷新是有代价的:在频繁执行的循环中,优先使用 '\n',让流自己决定何时刷新。只有在确实需要输出立刻显示时才使用 endl。
C++ 中如何读取包含空格的一整行文本?
使用 getline(cin, line),而不是 cin >> line。>> 运算符遇到第一个空白字符就停止,所以只能读到一个单词。getline 会把按下 Enter 之前的所有内容(包括空格)读入一个 std::string。