一、程序
在 C 语言中输入和输出的头文件是 #include <stdio.h>,而在 C++ 中标准输入输出头文件则是 #include <iostream>,它的作用和 stdio 类似,不过更为强大。
#include <iostream>
int main(){
std::cout<<"Hello World!"<<std::endl;
}
本文介绍 C++ 标准输入输出流 cin/cout 的基本用法,对比了 C 风格 scanf/printf 与 C++20 std::format 的优势。详细讲解了 cout 格式化输出的操纵符(如 setprecision、setw),以及性能优化技巧(关闭同步、解绑 cin)。同时涵盖自定义类型输出重载及常见错误处理。
在 C 语言中输入和输出的头文件是 #include <stdio.h>,而在 C++ 中标准输入输出头文件则是 #include <iostream>,它的作用和 stdio 类似,不过更为强大。
#include <iostream>
int main(){
std::cout<<"Hello World!"<<std::endl;
}
std::cout 的作用是在告诉程序我们在使用标准库里的 cout。\n 是一个意思,唯一的差别是在某些情况下,输出的内容可能并不一定会立即显示在终端上,而 endl 可以确保立即显示。简便写法:
#include <iostream>
using namespace std;
int main(){
cout<<"Hello World!"<<endl;
}
#include <iostream>
using namespace std;
int main(){
int a;
cin>>a;
cout<<a<<endl;
}
std::format 是 C++20 引入的类型安全的字符串格式化工具,核心定位是'统一且优雅的格式化解决方案',定义在 <format> 头文件中,核心能力包括:
cout/文件等输出;基础示例(生成格式化字符串后输出):
#include <iostream>
#include <format>
using namespace std;
int main() {
int age = 20;
double score = 95.567;
// 生成格式化字符串
string info = format("年龄:{:>3d},成绩:{:.2f}", age, score);
// 配合 cout 输出
cout << info << endl;
// 输出:年龄: 20,成绩:95.57
return 0;
}
| 语法格式 | 作用说明 | 示例代码 | 输出结果 |
|---|---|---|---|
{n} | 指定变量位置(n 从 0 开始) | format("{1} {0}", "B", "A") | A B |
{:.2f} | 浮点数保留 2 位小数 | format("{:.2f}", 3.1415) | 3.14 |
{:d} | 十进制整数(默认) | format("{:d}", 123) | 123 |
{:x}/{:X} | 十六进制(小写/大写) | format("{:X}", 255) | FF |
{:05d} | 整数补零到 5 位 | format("{:05d}", 123) | 00123 |
{:>8s} | 字符串右对齐,总宽度 8 | format("{:>8s}", "abc") | " abc" |
{:<8s} | 字符串左对齐,总宽度 8 | format("{:<8s}", "abc") | "abc " |
{:+d} | 显示整数符号(+/-) | format("{:+d}", -123) | -123 |
{:.3e} | 科学计数法,保留 3 位有效数字 | format("{:.3e}", 1234.56) | 1.235e+03 |
实战示例(组合规则):
#include <iostream>
#include <format>
using namespace std;
int main() {
int age = 25;
double salary = 12345.6789;
int id = 78;
// 组合格式化规则:位置 + 补零 + 小数精度
string info = format(
"员工 ID:{2:04d} | 年龄:{0:d} | 薪资:{1:+.2f}", age, salary, id
);
cout << info << endl;
// 输出:员工 ID:0078 | 年龄:25 | 薪资:+12345.68
return 0;
}
| 特性 | scanf/printf (C 风格) | cin/cout (C++ 流) | std::format + cin/cout (C++20) |
|---|---|---|---|
| 类型安全 | ❌ 不安全(编译期不检查) | ✅ 安全(编译期类型检查) | ✅ 安全(编译期严格检查) |
| 语法直观性 | ❌ 格式符繁琐(% d/% f/% s) | ✅ 语法简洁(>>/<<) | ✅ 占位符清晰({}) |
| 格式化能力 | ✅ 强(但格式符易出错) | ❌ 弱(格式化需额外操作) | ✅ 极强(灵活且易读) |
| 性能 | ✅ 快(接近底层) | ❌ 慢(默认同步 C 流) | ⚠️ 中等(略低于 printf,远高于 cout) |
| 扩展性 | ❌ 差(不支持自定义类型) | ✅ 强(重载 >>/<< 即可) | ✅ 极强(重载 formatter) |
| 兼容性 | ✅ 全兼容(所有 C/C++ 版本) | ✅ 兼容 C++98+ | ❌ 仅 C++20+(低版本需 fmtlib) |
| 错误处理 | ❌ 隐式错误(返回值易忽略) | ✅ 可通过流状态检查错误 | ✅ 抛出 format_error 异常 |
核心优势:
printf("%.2f %X", 3.14, 255))。核心痛点:
%d 接收 double 类型,编译不报错,运行时崩溃/输出乱码;Point{1,2})。核心优势:
cin >> int_var 只能接收整数,否则流状态置错;cin >> a >> b、cout << "age: " << age,无需记忆格式符;operator>>/operator<< 即可格式化自定义类。核心痛点:
ios::sync_with_stdio(false); cin.tie(nullptr); 优化,但仍不如 printf);cout << fixed << setprecision(2) << score,代码冗长;核心优势(对比前两者的核心提升):
printf("姓名:%s,年龄:%d,成绩:%.2f", name, age, score);format("姓名:{},年龄:{},成绩:{:.2f}", name, age, score);{1} {0});string s = format(...)),再按需输出到控制台/文件/网络,灵活性远超 printf/cout;formatter),且支持更多格式化场景(如容器、日期)。核心痛点:
fmtlib(format 的前身,语法完全兼容);cout 是 C++ 标准库 <iostream> 中定义的标准输出流对象,全称为 std::cout,核心作用是将数据输出到控制台(终端),是 C++ 替代 C 语言 printf 的面向对象输出方式,核心特点:
printf 的格式符匹配错误;<<(插入运算符)串联输出内容,无需记忆格式符;<< 运算符);stdio 流,可手动优化。只需包含核心头文件 <iostream>,新手可直接使用 using namespace std; 简化代码:
#include <iostream> // 必须包含的头文件
// 可选:避免每次写 std::cout
using namespace std;
| 语法/关键字 | 作用说明 | 示例代码 | 输出结果 |
|---|---|---|---|
cout << | 插入运算符,输出数据 | cout << 123; | 123 |
endl | 输出换行符并刷新缓冲区 | cout << "test" << endl; | test(换行) |
\n | 仅输出换行符(不刷新缓冲区,更快) | cout << "test\n"; | test(换行) |
boolalpha | 布尔值输出 true/false(而非 1/0) | cout << boolalpha << false; | false |
noboolalpha | 恢复布尔值数字输出 | cout << noboolalpha << true; | 1 |
flush | 手动刷新输出缓冲区 | cout << "test" << flush; | test(无换行) |
cout 本身格式化能力较弱,需配合 <iomanip> 头文件中的格式化操纵符,实现精度、对齐、进制等控制:
#include <iostream>
#include <iomanip> // 必须包含,提供格式化操纵符
using namespace std;
int main() {
double pi = 3.1415926;
int num = 255;
string str = "abc";
// 1. 浮点数精度控制(保留 2 位小数)
cout << "π保留 2 位小数:" << fixed << setprecision(2) << pi << endl;
// 输出:π保留 2 位小数:3.14
// 2. 进制转换(十进制/八进制/十六进制)
cout << "十进制:" << dec << num << endl; // 255
cout << "八进制:" << oct << num << endl; // 377
cout << "十六进制:" << hex << uppercase << num << endl; // FF(大写)
// 3. 对齐与补零(宽度 5,左对齐,补 0)
cout << "左对齐补 0:" << setw(5) << left << setfill('0') << str << endl;
// 输出:左对齐补 0:abc00
// 4. 恢复默认格式
cout << resetiosflags(ios::fixed | ios::uppercase);
return 0;
}
核心格式化操纵符(来自 <iomanip>):
| 操纵符 | 作用 |
|---|---|
setprecision(n) | 设置浮点数精度(n 为有效数字/小数位数,配合 fixed 为小数位数) |
fixed | 浮点数固定小数格式 |
scientific | 浮点数科学计数法格式 |
setw(n) | 设置输出宽度(仅对下一个输出有效) |
setfill(c) | 设置填充字符(默认空格) |
left/right | 左对齐/右对齐(默认右对齐) |
dec/oct/hex | 十进制/八进制/十六进制 |
uppercase | 十六进制/科学计数法大写输出 |
resetiosflags | 恢复格式化标志为默认 |
| 操纵符组合 | 效果 | 底层逻辑 |
|---|---|---|
setprecision(n) | 有效数字 n 位(默认模式) | 流状态:ios::defaultfloat,截断/四舍五入到 n 位有效数字 |
fixed + setprecision(n) | 小数位 n 位(固定格式) | 流状态:ios::fixed,强制显示小数点,小数部分保留 n 位 |
scientific + setprecision(n) | 科学计数法,小数位 n 位 | 流状态:ios::scientific,格式为 尾数 e±指数,尾数保留 n 位小数 |
完整示例:
int main() {
double pi = 3.141592653589793;
double num = 1234.5678;
// 场景 1:默认模式(有效数字,默认 6 位)
cout << "【默认模式】pi = " << pi << endl; // 输出:3.14159(6 位有效数字)
cout << "【默认模式】num = " << num << endl; // 输出:1234.57(6 位有效数字,四舍五入)
// 场景 2:修改有效数字为 4 位(永久生效,直到重置)
cout << "【有效数字 4 位】pi = " << setprecision(4) << pi << endl; // 3.142(4 位有效数字)
cout << "【有效数字 4 位】num = " << num << endl; // 1235(4 位有效数字,四舍五入)
// 场景 3:固定小数位模式(保留 2 位小数)
cout << "【固定 2 位小数】pi = " << fixed << setprecision(2) << pi << endl; // 3.14
cout << "【固定 2 位小数】num = " << num << endl; // 1234.57
// 场景 4:科学计数法(保留 3 位小数)
cout << "【科学计数法】pi = " << scientific << setprecision(3) << pi << endl; // 3.142e+00
cout << "【科学计数法】num = " << num << endl; // 1.235e+03
// 场景 5:重置所有浮点数格式(恢复默认)
cout << "【重置后】pi = " << resetiosflags(ios::fixed | ios::scientific) << setprecision(6) << pi << endl; // 3.14159(恢复默认 6 位有效数字)
return 0;
}
| 操纵符 | 效果 | 底层状态 | 示例(num=255) |
|---|---|---|---|
dec | 十进制 | ios::dec | 255 |
oct | 八进制 | ios::oct | 377 |
hex | 十六进制 | ios::hex | ff |
uppercase | 十六进制/科学计数法大写 | ios::uppercase | FF |
| 操纵符组合 | 效果 | 注意事项 |
|---|---|---|
setw(n) | 设置输出宽度 n(仅下一个有效) | 不足宽度时补空格,超出宽度时按实际输出(不会截断) |
setfill(c) | 设置填充字符(永久生效) | 必须配合 setw 使用,默认填充空格 |
left/right | 左/右对齐(永久生效) | 默认右对齐 |
完整示例(含坑点演示):
int main() {
int id = 123;
int num = 255;
// 场景 1:学号补零(宽度 5,右对齐,补 0)
cout << "【学号补零】" << setw(5) << setfill('0') << id << endl; // 00123
// 坑点:setw 仅对下一个有效,第二次输出 id 不会补零
cout << "【无 setw】" << id << endl; // 123(无补零)
// 场景 2:宽度 8,左对齐,补*
cout << "【左对齐补*】" << setw(8) << left << setfill('*') << id << endl; // 123*****
// 验证:left 永久生效,下一个输出仍左对齐
cout << "【左对齐延续】" << setw(8) << num << endl; // 255*****
// 场景 3:十六进制大写输出
cout << "【十六进制大写】" << hex << uppercase << num << endl; // FF
// 恢复十进制 + 默认对齐 + 填充空格
cout << resetiosflags(ios::uppercase) << dec << right << setfill(' ');
// 场景 4:宽度不足时不截断(重要)
cout << "【宽度不足】" << setw(2) << 1234 << endl; // 1234(不会截断为 34)
return 0;
}
| 操纵符 | 效果 | 示例(flag=true) |
|---|---|---|
boolalpha | 输出 true/false | true |
noboolalpha | 恢复输出 1/0(默认) | 1 |
示例:
int main() {
bool flag = true;
cout << "【默认布尔值】" << flag << endl; // 1
cout << "【boolalpha】" << boolalpha << flag << endl; // true
cout << "【恢复默认】" << noboolalpha << flag << endl; // 1
return 0;
}
字符串格式化逻辑与整数一致,重点注意 setw 仅对下一个字符串生效:
int main() {
string name = "张三";
// 宽度 10,右对齐,补-
cout << "【右对齐补-】" << setw(10) << setfill('-') << name << endl; // --------张三
// 宽度 10,左对齐,补-
cout << "【左对齐补-】" << left << setw(10) << name << endl; // 张三--------
return 0;
}
cout 默认会同步 C 语言的 printf 缓冲区,导致输出速度比 printf 慢很多,可通过以下两行代码优化(性能接近 printf):
#include <iostream>
using namespace std;
int main() {
// 核心优化:关闭 C/C++ 流同步 + 解绑 cin 与 cout
ios::sync_with_stdio(false);
cin.tie(nullptr);
// 大量输出测试(优化后速度提升 10 倍+)
for (int i = 0; i < 1000000; ++i) {
cout << i << '\n'; // 用 \n 代替 endl(避免频繁刷新缓冲区)
}
return 0;
}
优化关键说明:
ios::sync_with_stdio(false):关闭 cout 与 C 标准输出的同步,减少开销;cin.tie(nullptr):解绑 cin 和 cout(默认 cin 读取前会刷新 cout 缓冲区);\n 代替 endl:endl 会强制刷新缓冲区,大量输出时效率极低。通过重载 operator<< 运算符,可让 cout 直接输出自定义类/结构体:
#include <iostream>
#include <string>
using namespace std;
// 自定义结构体:学生
struct Student {
string name;
int age;
double score;
};
// 重载<<运算符(核心步骤)
ostream& operator<<(ostream& os, const Student& stu) {
// 自定义输出格式
os << "姓名:" << stu.name << ",年龄:" << stu.age << ",成绩:" << stu.score;
return os; // 返回 os 以支持链式输出
}
int main() {
Student s{"张三", 18, 95.5};
// 直接输出自定义类型
cout << s << endl; // 输出:姓名:张三,年龄:18,成绩:95.5
return 0;
}
system("chcp 65001");。setw 仅对下一个输出有效
setw,或先格式化字符串再输出。fixed 使用 setprecision,明确指定小数位数。cout 是 C++ 类型安全的标准输出工具,核心语法是 cout << 内容,endl 换行并刷新缓冲区(推荐用 \n 提升性能);<iomanip>,使用 setprecision/setw 等操纵符,语法比 printf 繁琐但类型安全;ios::sync_with_stdio(false) + 解绑 cin.tie(nullptr) + 用 \n 代替 endl;operator<< 运算符。
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online