stringstream:字符串当流用
更新时间:2026-08-27。本文是
languages/cpp/主题入门层第 7 篇。上一篇学会了 cast,这一篇介绍一个做字符串格式化、数字与字符串互转的利器std::stringstream。它把"流"的思想用到字符串上:用<<往字符串里写、用>>从字符串里读,还能当类型转换的万能桥梁。
本文要回答的问题
stringstream是什么?和cout/cin是什么关系?- 怎么用它做"数字 ↔ 字符串"转换和格式化?
- 相比
sprintf/atoi,它好在哪、要注意什么?
一、stringstream 是什么
cout / cin 是连着屏幕/键盘的流;std::stringstream 是把流接到字符串上——你用 << 往字符串里写数据,用 >> 从字符串里读数据,语法和 cout / cin 完全一致。
#include <iostream>
#include <sstream>
int main() {
std::stringstream ss;
ss << "age=" << 25; // 往"字符串流"里写
std::string result = ss.str(); // 取回字符串:"age=25"
std::cout << result << std::endl;
return 0;
}ss.str() 返回内部字符串。stringstream 生活在 <sstream> 头文件里,是 iostream 家族的一员,所以 << / >> 的用法和流操纵符(setw 等)全都能用。
二、数字 ↔ 字符串互转
数字 → 字符串
#include <sstream>
#include <string>
int n = 42;
double pi = 3.14159;
std::stringstream ss;
ss << n << " " << pi;
std::string s = ss.str(); // "42 3.14159"字符串 → 数字
std::stringstream ss("123 45.6");
int a;
double b;
ss >> a >> b; // a == 123, b == 45.6注意:>> 读到不匹配的字符会失败(和 cin 一样有失败标志),比如把 "abc" 转 int。判断是否成功:
std::stringstream ss("abc");
int n;
if (ss >> n) {
// 成功
} else {
// 失败:不是数字
}这就是 stringstream 当"万能转换器"的用法——比 C 的 atoi / sprintf 安全,因为失败是可见的,不会静默返回 0 或写坏缓冲区。
三、和 sprintf / atoi 对比
| 对比项 | C 写法 | stringstream 写法 |
|---|---|---|
| int → string | sprintf(buf, "%d", n) | ss << n; ss.str() |
| string → int | atoi(str) | ss >> n(可查失败) |
| 格式化 | %d %.2f %s | 流操纵符 setw/setprecision |
| 缓冲区 | 手动 char buf,易溢出 | 自动管理 |
| 失败检测 | atoi 返回 0(无法区分"转出0"和"失败") | >> 返回流状态,可检查 |
atoi("abc") 返回 0——你根本分不清是"转换成功得 0"还是"输入非法"。stringstream 的 >> 可以判断,这是它最实在的优势。
C++17 起还有更现代的替代:std::to_string(n)(数字→string,最简单)、std::from_chars(解析最快,但较底层)。入门阶段 stringstream 通用性最好,to_string 适合简单场景:
std::string s = std::to_string(42); // "42"四、格式化输出到字符串
结合上一篇的流操纵符,可以把格式化结果"装进字符串"而不是直接打印:
#include <sstream>
#include <iomanip>
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << 3.14159; // "3.14"
ss << std::setw(6) << 42; // 宽度6右对齐
std::string report = ss.str();这比 sprintf 拼长格式串可读性好,也避免手算缓冲区大小。生成日志、拼接消息、构造文件名都用得上。
五、常见坑与注意事项
>>读完要重置:同一个stringstream想反复读,需要ss.clear(); ss.str(new_content);——只str()不清错误标志,之前的失败会延续;ss >> a >> b的空白:>>默认跳过空白,所以"123 45.6"能正确拆;想按行读用std::getline(ss, line);- 性能:stringstream 转换比
std::to_string/from_chars慢(有格式化开销)。循环里大量转换时用std::to_string或from_chars(高手层流式 IO 深挖展开); str()返回拷贝:ss.str()返回的是 string 副本,频繁调用有拷贝开销,需要时保存一次。
六、与本站主线衔接
- 流式 IO 的底层缓冲与格式化机制,见高手层流式 IO 深挖;
- 日志系统、参数解析常依赖字符串流(综合练习篇命令行参数解析工具会用到);
- C 的
sprintf/sscanf对照,见 C 语言 fscanf 与 fprintf。
一句话总结
std::stringstream 把"流"用到字符串上——<< 写、>> 读、str() 取出,数字↔字符串互转和格式化都能干,比 sprintf/atoi 安全(失败可见、内存自动);常用 ss << x 拼字符串、ss >> n 解析数字,坑是复用前要 clear(),追求性能时换 to_string / from_chars。
上一篇:运算符与类型转换 下一篇:if / switch 分支