信奥必备:字符串流 stringstream 实战教程
在信息学奥林匹克竞赛(CSP-J/S、NOIP)中,字符串处理类题目是入门级高频考点,手写字符串类型转换不仅耗时,还可能因边界条件(如负数、多分隔符、不规则空格)出错。stringstream 是 C++ <sstream> 库的“轻量化神器”——它把字符串封装成“内存流”,让你像操作 cin/cout 一样处理字符串,能大幅简化代码、降低出错率,是信奥生必须掌握的基础工具。
前置知识(必记)
- 头文件:
#include <sstream>已包含在万能头#include <bits/stdc++.h>中。 - 核心操作:
<<:向流中写入数据(赋值/拼接);>>:从流中读取数据(按类型解析,自动忽略空格/制表符);str():获取流中完整字符串;str(""):清空流的内容;- 复用规则:多次使用同一个
stringstream时,必须先clear()(重置流状态,如结束符/错误标记),再str("")(清空内容),否则会读取失败。
场景1:[字符串 ↔ 数值]快速转换(替代手写/atoi)
适用情况
题目需要将字符串形式的数字(含负数、小数)转成 int/double,或把数值转成字符串;尤其适合处理“不确定位数的数字”和“带符号的数字”,避免手写遍历字符计算的麻烦。
适用题目(CSP-J 2020 模拟题)
题目描述:
输入一个仅包含整数的字符串(整数之间用单个空格分隔,可能有负数),求这些整数的和。
输入示例:"12 -3 45 0 -9"
输出示例:45
解题思路:
用 stringstream 读取整个字符串,通过 >> 逐个解析成 int,累加即可。相比手写转换(逐字符判断正负、计算位数),stringstream 能直接处理负数,且代码简单。
核心代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
getline(cin, s); // 读取整行输入(含空格)
stringstream ss(s); // 初始化流,传入待处理字符串
int num, sum = 0;
// 逐个读取整数(自动忽略空格,直到流结束)
while (ss >> num) {
sum += num;
}
cout << sum << endl; // 输出:45
return 0;
}
竞赛小贴士
atoi()仅支持正/负整数,且无法处理格式错误;stringstream支持int/double,且解析失败时仅会终止读取,不会直接崩溃;- 数值转字符串:
ss << 123; string res = ss.str();即可,比to_string()更灵活(支持多类型拼接)。
场景2:按自定义分隔符拆分字符串(替代手写split)
适用情况
输入字符串用非空格分隔符(如逗号、竖线、分号)分割子串,需要拆分出所有子串;替代手写 split 函数(遍历字符+判断分隔符),避免漏处理“首尾分隔符”“连续分隔符”等边界。
适用题目(NOIP 2018 普及组改编)
题目描述:
输入一行字符串,单词之间用逗号分隔(可能有首尾空格、逗号前后空格),统计不同单词的数量(忽略单词前后空格)。
输入示例:" apple,banana,apple,orange ,pear"
输出示例:4
解题思路:
1. 先用 stringstream 读取整行,自动忽略首尾空格;
2. 用 getline(ss, temp, ',') 按逗号拆分,拆分后再用 stringstream 去除每个单词的前后空格;
3. 存入 set 自动去重,最终 set 的大小即为答案。
核心代码:
#include <iostream>
#include <sstream>
#include <string>
#include <set>
using namespace std;
// 去除字符串首尾空格(竞赛常用工具函数)
string trim(const string& s) {
stringstream ss(s);
string res;
ss >> res; // >> 自动忽略首尾空格
return res;
}
int main() {
string s;
getline(cin, s);
stringstream ss(s);
string temp;
set<string> words; // 自动去重
// 按逗号拆分字符串
while (getline(ss, temp, ',')) {
string word = trim(temp); // 去除单词前后空格
if (!word.empty()) { // 避免空字符串(如连续逗号)
words.insert(word);
}
}
cout << words.size() << endl; // 输出:4
return 0;
}
竞赛小贴士
getline(ss, temp, 分隔符)是拆分核心,分隔符只能是单个字符(如,/|);- 若遇到多字符分隔符(如
||),需先替换成单字符,再用getline拆分。
总结(信奥必记)
- 核心适用场景:数值与字符串互转、自定义分隔符拆分、格式化拼接、不规则空格输入处理;
- 避坑关键:复用
stringstream时,必须先clear()(重置状态)再str("")(清空内容);
掌握 stringstream 后,信奥中棘手的字符串处理问题都能快速解决,建议结合上述案例综合记忆!
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com