IO库

掌握C++的输入输出体系——iostream/fstream/sstream三种流,文件读写、字符串流格式化、流状态管理

学习目标

  • 能比较并选择正确的流类型(iostream/fstream/sstream)完成输入输出——打开文件、逐行读取、用格式化操纵符对齐输出到控制台
  • 能分析并恢复流状态——通过 good()/fail()/eof() 判断读是否成功,并在读到 EOF 后用 clear()+seekg() 重新读取
  • 能回答:用 while (file >> num) 读文件里的整数,循环为什么会在读到末尾时自动停止?如果下一次再跑同样的循环会怎样?怎么修正?

机制总览

IO库:机制路径

  1. 1

    直觉:程序靠什么和外界说话?

    你已经用 cin 读键盘输入、用 cout 往屏幕上打字——这是程序和外界的两次对话。但真实的程序不会只和键盘屏幕打交道——它要读配置文件、写日志文件、解析 CSV 数据、把内存里的结果拼成格式化报告。

  2. 2

    IO 流家族:一张继承树看清三条分支

    在 C++ 里, 流(stream) 是你读写数据的统一通道。所有流类都源自同一个基础——一张继承树把三条分支清楚分开:

  3. 3

    官方 Chapter 8 的三层 IO 契约

    原书把这一章分成 IO 类、文件输入输出和 string 流三层。统一接口只是表面,真正需要掌握的是“操作、缓冲、条件状态”如何协作:一次提取可能成功并同时抵达文件尾,状态位也可能组合出现,输出进入缓冲并不代表外部设备已经持久化。

先按顺序建立机制,再进入实验切换阶段并检查失效证据。

章级决策实验

IO库:机制与证据

切换《IO库》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。

选择推理阶段

当前阶段 · 直觉:程序靠什么和外界说话?

你已经用 cin 读键盘输入、用 cout 往屏幕上打字——这是程序和外界的两次对话。但真实的程序不会只和键盘屏幕打交道——它要读配置文件、写日志文件、解析 CSV 数据、把内存里的结果拼成格式化报告。

可核验证据

保留编译诊断,运行本节最小示例,并用边界断言、对象计数或 sanitizer 复核「直觉:程序靠什么和外界说话?」的契约。

学完《IO库》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。

失效—证据矩阵

IO库:失效与核验

直觉:程序靠什么和外界说话?

典型失效

若把「直觉:程序靠什么和外界说话?」当作孤立语法点,忽略类型约束、对象生命周期或库契约,代码即使通过编译也可能破坏不变量。

核验证据

保留编译诊断,运行本节最小示例,并用边界断言、对象计数或 sanitizer 复核「直觉:程序靠什么和外界说话?」的契约。

IO 流家族:一张继承树看清三条分支

典型失效

若把「IO 流家族:一张继承树看清三条分支」当作孤立语法点,忽略类型约束、对象生命周期或库契约,代码即使通过编译也可能破坏不变量。

核验证据

保留编译诊断,运行本节最小示例,并用边界断言、对象计数或 sanitizer 复核「IO 流家族:一张继承树看清三条分支」的契约。

官方 Chapter 8 的三层 IO 契约

典型失效

若把「官方 Chapter 8 的三层 IO 契约」当作孤立语法点,忽略类型约束、对象生命周期或库契约,代码即使通过编译也可能破坏不变量。

核验证据

保留编译诊断,运行本节最小示例,并用边界断言、对象计数或 sanitizer 复核「官方 Chapter 8 的三层 IO 契约」的契约。

每个判断都必须能落到观测、测试或产物,不能只凭代码表面推测。

直觉:程序靠什么和外界说话?

你已经用 cin 读键盘输入、用 cout 往屏幕上打字——这是程序和外界的两次对话。但真实的程序不会只和键盘屏幕打交道——它要读配置文件、写日志文件、解析 CSV 数据、把内存里的结果拼成格式化报告。

想象一条工厂流水线:原料从进料口送进来,经过加工,成品从出料口送出去。进料口可以是手推车(键盘输入)、集装箱(文件)、小料斗(字符串)——但流水线上的加工步骤完全一样。C++ 提供的就是这样一条通用输送带——无论数据从哪来、去哪,你用的读写方式都一样。

没有这条通用输送带会怎样? 读写文件要学一套独有的做法、操作字符串又是另一套——每种数据源都是全新的用法,代码不能复用。这一章教你用同一套读写方式操作所有数据源——从此「在哪读、读到哪」是选的,不是重写的。

IO 流家族:一张继承树看清三条分支

在 C++ 里, 是你读写数据的统一通道。所有流类都源自同一个基础——一张继承树把三条分支清楚分开:

ios_baseiosistreamostreamistringstreamifstreamiostreamofstreamostringstreamfstreamstringstream基类派生类多重继承
C++ iostream 继承树:ios_base 是所有流类的根基,ios 管理格式状态,istream 管输入、ostream 管输出。 iostream 同时从两者继承;ifstream/ofstream/fstream 通过文件流类接管文件读写;istringstream/ostringstream/stringstream 在内存中操作字符串。

看上面的继承树——ios_base 是根,管理格式状态(精度、进制、宽度)和流状态(正常/失败/结束等)。ios 继承它,增加了对缓冲区的管理。从 ios 分出两条腿:istream(只负责读)和 ostream(只负责写)。然后三条分支各自展开:

  • 分支iostream 同时继承 istreamostream——既能读又能写。你每天用的 cin 就是 istream 对象,cout 就是 ostream 对象。cerr 的准确说法是默认启用 unitbuf 自动刷新,而不是承诺底层完全没有缓冲。

  • 分支ifstream(读文件)继承 istreamofstream(写文件)继承 ostreamfstream(读写文件)继承 iostream。所以 ifstream>>getline——和 cin 的用法一模一样。

  • 分支istringstream(读字符串)继承 istreamostringstream(写字符串)继承 ostreamstringstream(读写字符串)继承 iostream。所以 istringstreamcin 用法一样——只是数据来源变成了一段内存里的字符串。

三层共用同一个接口的根源:它们都继承自 ios_base 的格式状态和流状态管理,继承自 istream/ostream 的操作接口(>>/<</getline 等),还共用同一套 机制——这就是为什么对 cin 学会的东西在文件和字符串上完全能用。缓冲策略由具体流和设备决定,不能用固定字节数或固定倍数概括;通用 ostream 的析构也不等于一次可检查的成功刷新。

官方 Chapter 8 的三层 IO 契约

原书把这一章分成 IO 类、文件输入输出和 string 流三层。统一接口只是表面,真正需要掌握的是“操作、缓冲、条件状态”如何协作:一次提取可能成功并同时抵达文件尾,状态位也可能组合出现,输出进入缓冲并不代表外部设备已经持久化。

IO 类、条件状态与输出缓冲

IO 对象不能拷贝或赋值,所以接受或返回流的函数通常使用引用。读写函数也返回流引用,这才允许 out << a << b 连续操作。流的条件状态是位掩码而不是互斥枚举:eofbitfailbitbadbit 可以同时存在;只有状态值恰好为 goodbitgood() 才为真,而 fail() 会检查 failbitbadbit

流在布尔上下文中的判断基于 !fail()。因此 while (in >> value) 的准确含义是:先尝试一次提取,再检查提取后的流是否仍可用。它不等价于只检查状态而不读取的 while (!in.fail()),后者若把提取写在循环体内,很容易多处理一次旧值。

输出缓冲有几种常见提交时机:程序正常结束刷新标准输出、缓冲区满、使用 endlflush、设置 unitbuf,以及读取与之绑定的输入流。cin 默认绑定 cout,所以读取前会刷新提示文字。endl 同时写换行并刷新,普通 '\n' 只写换行;无需立刻显示或持久化时,不应为每行强制刷新。

std::cout << "name: " << std::flush; // 立刻显示提示
std::cin >> name;
 
auto *old = std::cin.tie(nullptr);    // 解除绑定,需自行管理刷新
std::cin.tie(old);                    // 恢复原绑定

对文件输出,析构会关闭文件并尝试提交缓冲,但析构阶段无法让调用者可靠处理写入失败。需要确认数据落盘时,应显式 flush()close(),随后检查流状态;磁盘已满、设备错误等情况不能被“RAII 一定不丢数据”掩盖。

文件流:把数据存到硬盘、从硬盘读回来

程序跑完数据就没了——除非你把它写进文件。 告诉流你要对文件做什么操作——只读?追加?还是覆盖?

模式组合有约束:trunc 需要同时启用 outapp 隐含输出且不能与 trunc 同用;ifstream 只能以输入为主,ofstream 只能以输出为主,fstream 才能组合 in | out。仅使用 out 打开现有文件通常会截断;要保留内容,应明确选择 app,或在 fstream 上组合 in | out 并自行定位。ate 只在打开时定位到末尾,之后仍可移动;app 则在每次写之前回到末尾。

用文件流做三件事:打开、读写、关闭。整个过程像一个闭环——打开把文件句柄领到手,读写操作数据,关闭归还句柄。看下面的 Stepper 演示每一步做了什么事。

文件流生命周期:一步一步走

先预测:文件只含 10 20 且末尾没有换行时,第二次成功读出 20eof()fail() 分别是什么?循环为了确认再无下一个整数而执行第三次提取后,两者又是什么?先写下答案,再用后面的状态图和 rdstate() 验证;关键是区分“已抵达末尾”和“本次没有提取到值”。

分步1 / 4

打开文件

先把 ifstream 对象构造起来——传入文件名和打开模式。构造瞬间系统去磁盘上找这个文件、准备好读取通道。

① 打开文件📄data.txtifstreamfile("data.txt");构造函数打开含文件/二进制模式② 读取数据▸▸▸▸▸file >> word;getline(file, line);file.read(buf, size);从硬盘→内存缓冲→变量③ 处理数据⚙️vector<string> words;统计·排序·过滤transform(begin,end,inserter)在内存中操作数据④ 关闭文件file.close();或析构函数自动关闭释放文件句柄·刷新缓冲🔓文件流生命周期打开 → 读取 → 处理 → 关闭
文件流从构造打开到析构关闭,中间经读取、处理两步——每一步对应不同的操作和内存状态。 即使不写 close(),析构函数也会自动关闭文件并刷新缓冲区。
#include <fstream>   // 文件流的头文件
#include <iostream>
 
int main() {
    std::ifstream file("data.txt");  // ① 构造即打开:打开名为 data.txt 的文件
    if (!file) {                     // ② 必须检查:文件不存在→构造失败→流进入fail状态
        std::cerr << "无法打开文件!\n";
        return 1;
    }
    // 现在 file 就绪——可以读了

打开模式可以组合——ios::in | ios::binary 同时指定读模式 + 禁止换行符转换(二进制数据必须加):

std::ifstream binFile("data.bin", std::ios::binary);  // 二进制读模式
std::ofstream log("app.log", std::ios::app);           // 追加写模式:新内容接在文件末尾

字符串流:字符串就是你的「临时控制台」

你需要把三个数字拼成 "scores: 85, 92, 78" 这种格式;你拿到一段 "Bob 85 90\r\n" 这样的字符串需要提取名字和分数——这些场景下, 是钥匙。

#include <sstream>
#include <iostream>
#include <string>
 
// 场景一:把多种类型拼成格式字符串——像 cout 一样往 string 里写
std::ostringstream oss;
oss << "scores: " << 85 << ", " << 92 << ", " << 78;
std::string result = oss.str();          // "scores: 85, 92, 78"
std::cout << result << std::endl;
 
// 场景二:从字符串中提取格式化数据——像 cin 一样从 string 里读
std::string raw = "Bob 85  90";
std::istringstream iss(raw);
std::string name;
int a, b;
iss >> name >> a >> b;                 // 单词 "Bob"、数字 85、数字 90
std::cout << name << " 总分: " << a + b << std::endl;  // Bob 总分: 175
 
// 场景三:逐行处理文本后用 stringstream 拆词
std::string line = "apple banana cherry";
std::istringstream words(line);
std::string w;
while (words >> w)                      // 逐个读出三个词
    std::cout << "[" << w << "] ";     // [apple] [banana] [cherry]

用 stringstream 代替直接字符串拼接的三大好处:① 自动处理类型转换——oss << 3.14159 不需要 to_string;② 格式化操纵符全支持——fixed << setprecision(2) 照样用;③ 测试方便——用 istringstream 模拟文件输入,不需要写临时文件。

流状态:每一步都知道「刚才读成功了吗」

你已经用了 while (file >> num) 这种写法——它为什么能在文件读完时自动停?因为每次 IO 操作后流内部有一组标志位记录着刚才的操作是否成功——这组标志构成了流的

good() == true流正常·上次操作成功eof() == true读到文件末尾fail() == true格式错/类型不匹配bad() == true流崩溃·不可恢复错误读到EOF格式错不可恢复错误clear()clear()检测与恢复rdstate()获取当前状态位掩码good() fail()eof() bad()逐一检查各状态标志clear()重置所有状态位setstate(flag)手动设置某个状态位流状态检查口诀while (file >> word) → 每次读完后自动检查 good,读到 EOF 或出错自动停止
C++ 流的四种状态:good(fail/eof/bad 都未设置)、eof(读到文件尾)、fail(格式错/数据不匹配,可恢复)、bad(流崩溃,不可恢复)。 通过 rdstate() 检查、clear() 重置——fail 和 eof 可恢复,bad 只能放弃流。

四种状态各司其职:

  • goodbit(值为 0):一切正常——good() 返回 true。上次操作成功,可以继续读。
  • eofbit:读到文件末尾——eof() 返回 true。不是错误——是「数据没更多了」的通知。
  • failbit:操作失败但流可恢复——比如试图把 "abc" 读进 int、或者已经 EOF 后再读。fail() 返回 true。
  • badbit:流崩溃、不可恢复——底层系统 IO 错误、缓冲区损坏。bad() 返回 true。这个流基本废了。

状态管理只靠三个操作:

std::ifstream file("data.txt");
auto state = file.rdstate();        // 读取当前状态(返回 iostate 掩码)
 
if (file.eof()) {
    file.clear();                   // 重置所有状态位——流恢复正常
    file.seekg(0, std::ios::beg);   // 把文件读取位置移回开头
    // 现在可以重新读一遍文件了
}
 
file.setstate(std::ios::failbit);   // 手动设置 failbit——模拟失败场景

失败提取后应先 clear() 再重新定位:C++11 的 seekg 会先清除 eofbit,但不会替你清掉 failbit 或 badbit;这些失败位仍在时定位不会按预期工作。稳定顺序是先恢复状态,再 seekg() 移位置,并检查定位结果。

格式化输出:让数字和文字排版整齐

往控制台或文件输出数据时——原始数字挤在一起根本没法看。C++ 的 就是排版工具——控制宽度、精度、进制、对齐方式。

操纵符效果示例std::setw(n)设置下一次输出的字段宽度为 n 个字符cout << setw(6) << 42; // " 42"std::setprecision(n)设置浮点数精度为 n 位cout << setprecision(3) << 3.14159; // 3.14std::fixed固定小数点格式(不是科学记数)cout << fixed << 3.14159; // 3.141590std::scientific科学记数法格式cout << scientific << 3.14159; // 3.141590e+00std::left输出内容左对齐(右侧补齐空格)cout << left << setw(6) << 42; // "42 "std::right输出内容右对齐(左侧补齐空格,默认)cout << right << setw(6) << 42; // " 42"std::hex以十六进制输出整数cout << hex << 255; // ffstd::oct以八进制输出整数cout << oct << 255; // 377std::dec恢复十进制输出整数(默认)cout << dec << 255; // 255std::boolalphabool值输出为 true/falsecout << boolalpha << true; // truestd::showbase显示进制前缀(0x 十六进制,0 八进制)cout << showbase << hex << 255; // 0xffhex/oct/fixed/scientific 等格式状态会持续生效。setw 仅影响下一次输出;使用前需包含 <iomanip>。
11 个最常用的 C++ 格式化操纵符。hex/oct/fixed/scientific 等一旦设置就持久生效;setw 只影响下一次输出。 全部定义在 <iomanip> 头文件中。

操纵符分两类——记忆规则就是「width 只用一次,其他持久生效」:

仅一次生效(用完就忘):

#include <iomanip>
std::cout << std::setw(6) << 42 << std::setw(6) << 100;
// 输出:    42   100(每个字段占 6 个字符宽度,右对齐)

持久生效(设一次影响后续所有输出):

std::cout << std::fixed << std::setprecision(3);   // 这一行设好格式
std::cout << 3.14159 << '\n';  // 3.142(固定小数 + 3 位精度)
std::cout << 2.71828 << '\n';  // 2.718(格式持续生效)
std::cout << std::defaultfloat; // 恢复默认浮点格式

最常见的格式化输出模板——靠左排名字、靠右排分数,每列宽度固定:

#include <iostream>
#include <iomanip>
#include <string>
 
int main() {
    struct { std::string name; int score; } data[] = {
        {"Alice", 92}, {"Bob", 85}, {"Charlie", 78}
    };
 
    // 表头
    std::cout << std::left  << std::setw(12) << "姓名"
              << std::right << std::setw(8)  << "分数\n";
    std::cout << std::string(20, '-') << '\n';
 
    // 数据行
    for (auto &d : data)
        std::cout << std::left  << std::setw(12) << d.name
                  << std::right << std::setw(8)  << d.score << '\n';
}
// 输出:
// 姓名          分数
// --------------------
// Alice             92
// Bob               85
// Charlie           78

实战:一个完整的文件处理程序

把本章所有知识点拧在一起——写一个程序:读取 input.txt 文件,统计每个单词出现的次数,按词频降序输出到 output.txt,带格式化的对齐表格。

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <iomanip>
 
int main() {
    // 第一步:打开输入文件(ifstream 构造 + 立即检查)
    std::ifstream in("input.txt");
    if (!in) {
        std::cerr << "无法打开 input.txt\n";
        return 1;
    }

检查文件是否打开成功是第一条纪律——if (!in) 在构造后立即判断。所有 IO 对象都可以放在布尔上下文中——等于 !fail()

    // 第二步:逐行读取,每行用 stringstream 拆词
    std::map<std::string, int> freq;
    std::string line;
    while (std::getline(in, line)) {
        std::istringstream iss(line);
        std::string word;
        while (iss >> word)       // sstream 的 >> 自动按空白切词
            freq[word]++;         // map::operator[] 不存在的 key 默认值 0
    }
    in.close();  // 读完就关——尽早释放文件句柄

getline(文件, line) → istringstream(line) → iss >> word 是逐行处理的标准三板斧。比起直接在文件上 >>,这样能逐行把控——一行出错不会影响其他行。

    // 第三步:排序——map 按 key 排,需要按 value 排就转 vector
    std::vector<std::pair<std::string, int>> items(freq.begin(), freq.end());
    std::sort(items.begin(), items.end(),
              [](auto &a, auto &b) { return a.second > b.second; });

std::map 自动按 key(单词)排序——要按 value(词频)排序,把它倒进 vector<pair> 再用自定义比较函数。

    // 第四步:格式化输出到文件
    std::ofstream out("output.txt");
    if (!out) {
        std::cerr << "无法创建 output.txt\n";
        return 1;
    }
    out << std::left << std::setw(20) << "单词"
        << std::right << std::setw(8) << "次数\n";
    out << std::string(28, '-') << '\n';
    for (auto &[word, count] : items)
        out << std::left << std::setw(20) << word
            << std::right << std::setw(8) << count << '\n';
    // out 离开作用域自动析构——自动 close + flush
}

left 让单词左对齐、right 让数字右对齐、setw 给每列固定宽度——一套操纵符把原始数据变成可阅读的表格。ofstream 对象不用手动 close——析构函数替你做了。

容易踩的坑

小结

  • C++ IO 库由 iostream(控制台)、fstream(文件)、sstream(字符串)三族组成——都继承自 ios_base/ios/istream/ostream 体系,共享 >>/<</getline 等相同接口
  • 文件流通过构造打开、析构关闭——打开后立即检查 !file,读模式用 >>getline,二进制模式加 ios::binary 并用 write()/read() 代替 <</>>
  • 字符串流让字符串拥有流操作能力——ostringstream 像 cout 一样把数据拼进 string,istringstream 像 cin 一样从 string 提取数据
  • 流状态用 good()/fail()/eof()/bad() 检测——eof 后重新读需先 clear()seekg()while (file >> x) 是最高频的正确读法
  • 格式化操纵符控制输出外观——setw 只影响下一次,fixed/hex/left 等持久生效;setprecision 的含义在 defaultfloat 和 fixed 下完全不同

练习

问题 1(改代码型) 下面这段代码从文件读取整数并求和——但它有一个常见 bug:第一行是标题 "Scores:",导致程序不能正确处理。找出 bug 并写出修正后的代码。

#include <iostream>
#include <fstream>
int main() {
    std::ifstream file("scores.txt");  // 第一行: "Scores:"
    int total = 0, count = 0, val;
    while (file >> val) {
        total += val;
        count++;
    }
    std::cout << "总和: " << total << ", 平均: "
              << static_cast<double>(total) / count << '\n';
    return 0;
}

问题 2(独立实现题) 写一个程序:读取 data.txt 文件(每行是 姓名 数学 语文 英语 的格式,如 "Alice 92 88 95"),计算每个人的平均分,把结果输出到 results.txt——格式化成整齐的表格(名字左对齐 12 字符、各科右对齐 6 字符、平均分右对齐 8 字符且保留一位小数)。输出示例:"Alice 92 88 95 91.7"

问题 3(问答型) 本章 §5 Stepper 演示了文件流生命周期——从打开、读取、处理到关闭。如果把整个程序改成「所有数据源一律从 istream & 引用参数传入」,文件的读法和键盘的读法在一个函数里怎么统一?写出函数签名和简短的调用示例。

名词解释

名词解释

本章出现的专业名词,用大白话再讲一遍。

流(stream)

C++ 输入输出的抽象概念。流是一个字符序列——你可以从中读取字符(输入流)或向其写入字符(输出流)。C++ 标准库提供了统一的流接口(>><< 运算符、getline 等),无论数据来自键盘、文件还是内存字符串,操作方式完全一致。详见本章「IO 流家族」一节的继承树图。

iostream

标准控制台 IO 流,包含 cin(标准输入)、cout(标准输出)、cerr 和 clog(标准错误/日志)。cerr 默认启用 unitbuf,每次输出操作后刷新,但不应简单等同于底层完全无缓冲。引入 iostream 头文件即可使用。详见本章「IO 流家族」。

fstream

文件 IO 流。ifstream 从文件读取,ofstream 写入文件,fstream 同时读写同一个文件。通过构造函数的文件名参数打开文件,析构时自动关闭。支持多种打开模式(in/out/app/ate/trunc/binary,可用 | 组合)。对 ifstream 用 >> 和 getline 的方式和 cin 完全一样——因为它们都继承自 istream。详见本章「文件流」一节和 Stepper 演示。

sstream

字符串 IO 流。istringstream 从字符串中读取(像 cin 从键盘读一样从内存字符串读),ostringstream 把各种类型的数据拼接输出到字符串(像 cout 打到屏幕一样打到 string),stringstream 同时支持读写。用法和 cin/cout 完全一致——只是数据源/目标从键盘屏幕换成了字符串。详见本章「字符串流」一节的代码示例。

str() 方法

ostringstream/stringstream 对象的成员函数。ostringstream::str() 返回流中全部已写入内容的 string 副本——相当于把输出流里的所有东西收成一根字符串。详见本章「字符串流」一节的代码示例。

打开模式(open mode)

打开文件时指定的位掩码。in 读、out 写、app 在每次写前定位到末尾、ate 只在打开后定位一次、trunc 清空、binary 禁止文本模式转换。app 并不自动提供跨进程写入原子性;并发写文件仍需额外同步。多个模式可用按位或组合。详见「文件流」。

流状态(stream state)

C++ 流对象内部的一组标志位(iostate 枚举),用于跟踪最近一次 IO 操作的结果。四种可能:goodbit(一切正常)、eofbit(读到文件末尾)、failbit(操作失败但流可恢复——如格式错)、badbit(流已崩溃、不可恢复——如底层 IO 错误)。通过 rdstate() 获取当前掩码,good()/eof()/fail()/bad() 分别检查各个位,clear() 重置所有状态位恢复为可用。详见本章「流状态」一节的 StreamStateDiagram 图示。

缓冲区(buffer)

由 streambuf 管理、位于程序值与外部设备之间的字符区域。它减少设备访问并维护读写位置;输出可因缓冲满、flush、unitbuf、关联流操作或文件关闭而提交。缓冲大小与策略由实现和设备决定,析构关闭也不能证明外部写入必然成功。

格式化操纵符(manipulator)

对 IO 流插入(<<)或提取(>>)的特殊函数或对象,用来改变流的格式行为。如 std::setw(n) 设字段宽度、std::fixed 固定小数格式、std::hex 切换进制、std::left/right 控制对齐方向。定义在 <iomanip> 头文件。注意 setw 只对下一次输出生效(用完自动重置为 0),其余(fixed/hex/left 等)一旦设置就持久生效。详见本章「格式化输出」一节的 IOManipulatorTable 速查表。

资料与写作方式声明

本章以C++ Primer, Fifth Edition, Chapter 8: The IO Library权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…