📄 一句话概括
C++ 把输入输出抽象成"流"——cout 是一个输出流对象、cin 是一个输入流对象,<< 和 >> 是往流里"推"和从流里"抽"的动作。cin 有三条解析规则:① 自动跳过前导空白(所以空格和回车都能当分隔符);② 按目标变量的类型读(读 int 遇到字母就停);③ 读不下去就"罢工"——流进入失败状态,后面所有读取全部失效。最后一条是隐藏最深的坑,也是"输入必须校验"的根因。
一、流是什么:一块"数据通道"
cout << "Hello"; // cout 是输出流对象,<< 把数据推进去
int a;
cin >> a; // cin 是输入流对象,>> 把数据抽出来
技术上的叫法(认识一下就行):
cout的类型是ostream(output stream)cin的类型是istream(input stream)<<叫插入运算符、>>叫提取运算符——它们本来是"位移运算符",被 C++ 重载成了输入输出符号(第 8 章讲重载)
为什么 cin >> a 不用写 &a(C 语言要):因为 C++ 用引用机制把变量直接交给 cin(第 7 章讲引用)。
二、缓冲区:为什么要"先攒着"
你敲了一串字符,按回车
↓
先进入【缓冲区】(一块临时内存)
↓
cin 从缓冲区里按需要取
缓冲区带来的三个现象:
- 可以一次输入多个值:
7 3一次性喂给cin >> a >> b - 空格与回车等价:它们都只是"分隔符",所以输入
7 3、7 3、7回车3结果一样 - 多余的内容留在缓冲区:等你下一次读取——这既是便利(连续读),也是坑(比如残留的回车会影响后面的读取)
三、cin 的三条解析规则
规则一:自动跳过前导空白
int a, b;
cin >> a >> b; // 输入 " 7 3 " 也没问题,空白自动跳过
空白包括:空格、制表符(Tab)、换行符。
规则二:按目标变量的类型解析
| 目标类型 | 它会怎么读 | 遇到什么停 |
|---|---|---|
int |
找一串数字 | 遇到字母、小数点、空白就停 |
double |
找数字,认小数点和指数 | 遇到字母停 |
char |
读一个非空白字符 | 立刻停(注意:会跳过空白!) |
bool |
只认 0 和 1 |
其他都失败 |
规则三:读不下去就"罢工"(这条最重要)
int a, b, c;
cin >> a >> b >> c; // 你输入:7 abc 9
会发生什么:
a得到 7 —— 正常- 读
b时遇到abc,解析失败 →b拿到一个不确定的值(C++11 后置 0) - 流进入失败状态:
cin"卡住了",后面读c直接失败,c也不会被赋值 - 而且这个失败状态会一直保持,直到你手动清除(
cin.clear())
所以真实程序必须校验输入(第 4 章会用循环"逼用户重新输入")。一个输错,后面全乱——这就是本节最值钱的一句话。
四、endl 与 "\n" 的区别
cout << "abc" << endl; // 换行 + 【刷新缓冲区】
cout << "abc" << "\n"; // 只换行,不强制刷新
| 动作 | |
|---|---|
endl |
换行 + 立刻把缓冲区内容送出去(flush) |
"\n" |
只换行(什么时候真正写出去由系统决定) |
什么时候在意:程序崩溃时,还没刷出去的内容会丢——这也是 cerr 设计成"不缓冲"的原因(2.1.2)。入门阶段都用 endl 就好,等追求性能时再换 "\n"。
五、动手 Demo:三个实验看清规则
新建 stream2.cpp:
#include <iostream>
using namespace std;
int main() {
int a, b;
// 实验一:空格与回车等价
cout << "输入两个整数(空格或回车分开):";
cin >> a >> b;
cout << "a = " << a << " b = " << b << endl;
// 实验二:读字符会跳过空白
char c;
cout << "随便输几个字符,中间夹空格:";
cin >> c;
cout << "读到的是:" << c << "(空白被跳过了)" << endl;
// 实验三:故意输错,看流罢工
int x, y;
cout << "输入两个整数,但第二个故意输字母:";
cin >> x >> y;
cout << "x = " << x << " y = " << y << "(y 很可能不是你想的)" << endl;
return 0;
}
看到什么算成功:
- 实验一两行用不同分隔方式,结果完全一样
- 实验二里即使你在字符前打了空格,读到的仍是那个字符
- 实验三里 y 拿到一个"不对的值"(在 C++11 之后通常是 0),说明流在失败后不再正常工作
30 秒实验:在实验三之后再加一句 cin >> x;,看它能不能读到东西——读不到(流还卡在失败状态)。要恢复必须 cin.clear(); 并清掉缓冲区里的残留字符。
六、常见误区
- "
cin >> a >> b必须让用户按两次回车"——不用。空格和回车都能分隔 - "输入错了重新输一次就行"——不行。流会进入失败状态并卡住,必须显式清除(
cin.clear()) - "
cin >> c能读到空格"——不能,空白被跳过了。要读含空格的整行,得用getline(第 6 章) - "
endl和\n完全一样"——endl多做了"刷新缓冲区"这件事。大多数情况没差别,但崩溃丢输出的场景下差别很致命
自测四问(点开对答案)
1. `cin` 为什么会自动跳过空格?——因为**空白(空格/Tab/回车)只是分隔符**,`cin` 会跳过前导空白再开始解析。 2. `cin >> a >> b` 输入 `7 3` 与 `7` 回车 `3` 有区别吗?——**没有**,两者等价。 3. 输入类型不符时会怎样?——**流进入失败状态**:当前变量拿到不确定值,**后续所有读取都失败**,直到调用 `cin.clear()` 清除。 4. `endl` 和 `"\n"` 的区别?——`endl` = 换行 **+ 刷新缓冲**;`"\n"` 只换行。- ☑ 流输出格式控制
相关笔记
- 数据的输入与输出 —— I/O 总览与四步套路
- 控制台屏幕 —— 三条通道与重定向
- iostream 标准库 ——
cout/cerr/clog的差别