cs106l-lecture-2-streams

Course: 斯坦福大学: C++标准库编程 | C++ Standard Library Programming


🎮 CS106L Lecture 2 — Streams

🏛 课程:Stanford CS106L — Standard C++ Programming Language

📍 主题:C++ 流(Streams)与输入输出系统

🎯 目标:理解 C++ 的 I/O 抽象模型、字符串流与状态位机制


C++ 中的 流(Stream) 是所有输入输出的统一抽象层。

它隐藏了设备差异,让我们以一致的方式与文件、键盘、网络交互。

“在 C++ 眼中,一切输入输出都是流。”

这堂课教你:

1️⃣ 流的核心概念与层次结构

2️⃣ 如何使用 ostringstreamistringstream

3️⃣ 如何检查流状态与避免输入错误

4️⃣ 如何使用 manipulators 控制输出格式


Stream|流抽象

ostringstream|输出字符串流

istringstream|输入字符串流

good / fail / eof / bad|状态位

flush / endl|缓冲刷新

manipulators|操纵符


流是数据的“河流”。

你写入输出流(out),数据顺流而下;

你从输入流(in)读取,数据逆流而上。

一切 I/O 都是流动的概念。



流(std::istream, std::ostream)是 C++ I/O 的根本抽象。

它屏蔽设备类型:无论来自键盘、文件或字符串,都能以相同方式操作。

📦 输出示例:

std::cout << "Hello, CS106L!" << std::endl;

📦 输入示例:

int x;
std::cin >> x;

« 与 » 是 流操作符(overloaded operators),

在不同类型上表现不同。

🧠 C++ 的流体系结构:

iostream
 ├── istream      → std::cin, ifstream, istringstream
 ├── ostream      → std::cout, ofstream, ostringstream
 └── iostream     → 双向流(文件/网络)

在现代 C++ 中,不再直接操作 char*。

std::string 可以无缝与流协作。

📦 示例:

std::string name;
std::cout << "Enter your name: ";
std::cin >> name;
std::cout << "Hello, " << name << "!" << std::endl;

std::string 自动管理内存与长度,不需手动释放。


std::ostringstream 将数据写入内存中的字符串缓冲区,而非屏幕。

📦 示例:

std::ostringstream oss;
oss << "Pi is approximately " << 3.14159;
std::string s = oss.str(); // 将流内容取出为 string
std::cout << s;  // 输出: Pi is approximately 3.14159

🧩 用途:

  • 动态拼接字符串
  • 生成日志、格式化输出
  • 替代 sprintf(),更安全

std::istringstream 从字符串中读取数据,就像从文件或键盘读一样。

📦 示例:

std::string data = "42 3.14 hello";
std::istringstream iss(data);

int x; double y; std::string word;
iss >> x >> y >> word;

std::cout << x << " | " << y << " | " << word << std::endl;
// 输出: 42 | 3.14 | hello

🧩 用途:

  • 从字符串中解析多种类型
  • 简化输入格式处理
  • 替代手写的字符串切割与转换逻辑

每个输入流都维护一组状态位,表示读取状态:

状态含义
.good()一切正常
.fail()读取失败(类型不匹配)
.eof()已到文件/输入结尾
.bad()严重错误(如硬件损坏)

📦 示例:

std::istringstream iss("abc");
int x;
iss >> x;
if (iss.fail()) std::cout << "Type mismatch!" << std::endl;

🧩 使用场景:

  • 检查输入是否合法
  • 判断是否读完文件
  • 清除错误状态 .clear()

C++ 的输出流是缓冲的

std::cout 不一定立即显示输出内容。

操作符作用
std::endl输出换行并刷新缓冲区(性能较慢)
'\n'仅换行,不刷新(更高效)
std::flush手动刷新缓冲区

📦 性能对比示例:

for (int i=0; i<100000; ++i)
    std::cout << i << '\n';      // ✅ 快
// vs
for (int i=0; i<100000; ++i)
    std::cout << i << std::endl; // ⚠️ 慢,频繁刷新

🧩 建议:

平时用 ‘\n’,除非你真的需要立刻看到输出结果。


C++ 提供大量操纵符来控制流格式。

操纵符功能
std::setw(n)设置字段宽度
std::setprecision(n)设置浮点精度
std::fixed / std::scientific控制浮点输出样式
std::boolalpha输出 true/false 而非 1/0

📦 示例:

std::cout << std::setw(8) << std::setprecision(3)
          << std::fixed << 3.1415926 << std::endl;
// 输出:    3.142

manipulators 是流的“修饰器”,它们链式修改输出行为。


“流如水,入出皆通;

写入缓冲,读出如风;

fail 不慌,clear 复用;

endl 慢,\n 才雄。”


练习 1:字符串拼接日志系统

使用 std::ostringstream 拼接输出:

std::ostringstream log;
log << "[INFO] Frame time = " << 16.7 << " ms";
std::cout << log.str();

练习 2:命令行解析器

从字符串 "move 12 8" 中提取指令与数字参数。

std::istringstream iss("move 12 8");
std::string cmd; int x, y;
iss >> cmd >> x >> y;

练习 3:状态检查

输入错误数据 "abc" 并检测 .fail()


  • 写工具或引擎日志时,优先使用 ostringstream 而非字符串拼接。
  • 对用户输入要始终检查 .fail() 状态。
  • 读取配置文件(如 .ini, .cfg)可用 istringstream 分析每一行。
  • 使用 '\n' 替代 std::endl 提升性能。

类别名称用途
输入流std::cin, std::ifstream, std::istringstream读取
输出流std::cout, std::ofstream, std::ostringstream写入
状态检测.good(), .fail(), .eof()检查错误
缓冲控制'\n', std::endl, std::flush刷新机制

“掌握流,就掌握了 C++ 世界的输入与输出之门。”


是否希望我继续为你整理 第 3 讲《Containers》(vector、map、unordered_map)

并保持相同 Notion 风格输出?