peek()是istream类的成员函数,用于非破坏性预读下一个字符,返回其ASCII码值(int型),不移动读取指针;若流已结束则返回EOF(-1)。

用 peek() 查看下一个输入字符但不提取
peek() 是 std::istream(如 std::cin)提供的成员函数,它返回下一个待读取的字符的整数值(int 类型),但不从输入缓冲区中移除该字符。如果输入流已到末尾或出错,返回 std::char_traits<char>::eof()</char>(通常是 -1)。
常见错误是误用 get() 或直接 >> 运算符——它们都会消费字符;而 peek() 是唯一标准、轻量、无副作用的“窥探”方式。
- 必须检查返回值是否为
EOF,否则可能把-1当作有效字符处理(比如误判为'ÿ') - 返回类型是
int,不是char,避免符号扩展问题(尤其在处理char为有符号平台时) - 连续多次调用
peek()总是返回同一个字符,直到有其他提取操作(如get()、>>或ignore())发生
为什么不用 unget() 回退来模拟 peek
有人尝试先 get() 再 unget(),以为等价于 peek(),但这是危险的:
-
unget()不保证成功:流可能不支持回退(如某些重定向输入或文件流在特定模式下),失败时会设置failbit - 即使成功,
unget()可能改变流状态(例如影响后续gcount()或格式化读取行为) - 性能更差:涉及一次实际读取 + 一次回退操作,而
peek()通常只是访问缓冲区首字节 -
unget()最多只允许回退一个字符,且不能连续unget()多次(未定义行为)
peek() 在条件分支和循环中的典型用法
最常见场景是根据下一个字符决定解析策略,比如跳过空白、识别分隔符、预判数字/字母开头:
立即学习“C++免费学习笔记(深入)”;
while (std::cin.peek() == ' ') {
std::cin.get(); // 真正吃掉空格
}
if (std::cin.peek() == '0') {
std::cin.ignore(1); // 吃掉前导零
// 接着读八进制或十六进制...
}
if (std::cin.peek() >= '0' && std::cin.peek() <= '9') {
int n;
std::cin >> n; // 安全:确认了下一个确实是数字
}
注意:peek() 返回的是 int,比较时应与 int 字面量(如 ' ')比较,编译器会自动提升 —— 但不要写成 (char)std::cin.peek() == ' ',这会截断 EOF 导致逻辑错误。
和 cin.rdbuf()->sgetc() 的区别
sgetc() 是底层 streambuf 接口,行为类似 peek(),但属于实现细节层级:
-
peek()是面向用户的、语义清晰的标准接口;sgetc()是面向缓冲区的、更底层的操作 -
sgetc()在缓冲区为空时可能触发实际 I/O(取决于具体streambuf实现),而peek()语义上更强调“不引发输入”,实际中两者在标准库中通常一致,但可移植性上peek()更稳 - 除非你在写自定义流缓冲区或深度调试 IO 行为,否则没必要绕过
peek()直接调用sgetc()
真正容易被忽略的是:如果输入流绑定了输出流(如默认的 cin 绑定到 cout),在调用 peek() 前未刷新输出,可能导致交互式输入卡住——这不是 peek() 的问题,但常在此类场景下暴露。


















