引言
在前面的文章中,我们系统学习了 C++ 异常处理、IO 流体系等核心特性。从本文开始,我们将进入 C++ 标准库中最重要的组成部分------STL(Standard Template Library,标准模板库)的学习。
STL 包含三大核心组件:容器 (Containers)、算法 (Algorithms)和迭代器 (Iterators)。本文将首先介绍字符串流(strstream)的用法作为过渡,然后深入讲解最常用的顺序容器------vector。

第一部分:字符串流 strstream
一、什么是字符串流
字符串流是一种特殊的内存流,它以字符数组作为输入/输出的缓冲区。可以理解为把字符串当作文件来读写。
cpp
#include <strstream> // 字符串流头文件(已废弃,但教材中常见)
#include <sstream> // 现代 C++ 推荐的字符串流头文件
注意 :
<strstream>在 C++98 中已被标记为废弃(deprecated),C++17 中彻底移除。现代 C++ 应使用<sstream>中的istringstream、ostringstream、stringstream。但考虑到很多教材和旧代码仍在使用,本文会讲解两种方式。
二、输入字符串流 istrstream
从字符数组中读取数据,就像从文件中读取一样。
cpp
#include <iostream>
#include <strstream>
using namespace std;
int main() {
// 1. 创建字符流对象,绑定到字符数组
char buf[] = "123567";
istrstream iss(buf);
// 2. 获取字符流的大小
iss.seekg(0, ios::end); // 移到末尾
streampos len = iss.tellg(); // 获取位置(即大小)
cout << "字符流的大小: " << len << endl;
// 3. 回到开头,逐个字符读取
iss.seekg(0, ios::beg);
char c;
int i = 0;
while (i < len) {
iss.get(c);
cout << c;
i++;
}
cout << endl;
return 0;
}
关键操作:
| 操作 | 说明 |
|---|---|
iss.seekg(0, ios::end) |
移动读指针到末尾 |
iss.tellg() |
获取当前读指针位置 |
iss.seekg(0, ios::beg) |
移动读指针到开头 |
iss.get(c) |
读取一个字符 |
三、输出字符串流 ostrstream
向字符数组中写入数据,就像向文件中写入一样。
cpp
#include <iostream>
#include <strstream>
#include <cstring>
using namespace std;
int main() {
// 1. 创建足够大的缓冲区
char* bufp = new char[1024]{0};
ostrstream oss(bufp, 1024);
int opt = 0;
while (1) {
// 检查缓冲区是否已满
if (oss.tellp() >= 1024) break;
cout << "1.录入一行 2.打印所有 3.清空 0.退出\n";
cin >> opt;
if (opt == 0) break;
else if (opt == 1) {
// 录入一行数据
cin.get(); // 清除残留的换行符
char line[32] = "";
cin.getline(line, 32);
oss.write(line, strlen(line)); // 写入内容
oss.put('\n'); // 写入换行符
}
else if (opt == 2) {
// 打印所有行
cout << string(30, '-') << endl;
istrstream iss(bufp, (int)oss.tellp());
while (!iss.eof()) {
char line[32] = "";
iss.getline(line, 32);
cout << line << endl;
}
}
else if (opt == 3) {
// 清空缓冲区
oss.seekp(0); // 写指针回到开头
memset(bufp, 0, 1024); // 清零
}
}
delete[] bufp;
return 0;
}
关键操作:
| 操作 | 说明 |
|---|---|
oss.write(buf, len) |
写入指定长度的数据 |
oss.put(ch) |
写入一个字符 |
oss.tellp() |
获取当前写指针位置(已写入的字节数) |
oss.seekp(0) |
将写指针移回开头 |
四、字符串流的数据流向

五、现代 C++ 的替代方案(sstream)
cpp
#include <sstream>
#include <string>
// 输出字符串流
ostringstream oss;
oss << "Hello" << 123 << 3.14;
string result = oss.str(); // 获取写入的字符串
// 输入字符串流
istringstream iss("123 456 789");
int a, b, c;
iss >> a >> b >> c; // 从字符串中格式化读取
第二部分:vector 容器
一、什么是 vector
vector 是 C++ STL 中最常用的顺序容器,本质上是一个动态数组。

二、基本操作
cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 1. 创建 vector
vector<int> v1(10); // 10 个元素,默认值为 0
vector<int> v2(10, 5); // 10 个元素,初始值都是 5
// 2. 尾部插入
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
// 3. 访问元素
cout << v1[0] << endl; // 下标访问(不检查越界)
cout << v1.at(1) << endl; // at() 访问(检查越界)
cout << v1.front() << endl; // 第一个元素
cout << v1.back() << endl; // 最后一个元素
// 4. 删除尾部元素
v1.pop_back();
// 5. 大小和容量
cout << "size: " << v1.size() << endl; // 元素个数
cout << "capacity: " << v1.capacity() << endl; // 当前容量
cout << "empty: " << v1.empty() << endl; // 是否为空
// 6. 清空
v1.clear(); // 清空所有元素,size=0
return 0;
}
三、迭代器
迭代器是 STL 的核心概念,可以理解为泛化的指针。
cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
// 获取迭代器
vector<int>::iterator it1 = v1.begin(); // 指向第一个元素
vector<int>::iterator it2 = v1.end(); // 指向最后一个元素之后
// 使用迭代器遍历
for (vector<int>::iterator it = v1.begin(); it != v1.end(); ++it) {
cout << *it << " "; // 解引用获取元素值
}
cout << endl;
// C++11 范围 for 循环(底层使用迭代器)
for (int val : v1) {
cout << val << " ";
}
return 0;
}
迭代器类型:

四、insert 与 erase
cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
// 在指定位置插入
vector<int>::iterator it = v1.begin();
it = v1.insert(it, 8); // 在开头插入 8
v1.insert(it + 1, 7); // 在第二个位置插入 7
// 遍历打印
for (int val : v1) {
cout << val << " "; // 输出: 8 7 10 20 30
}
cout << endl;
// 删除指定元素
v1.erase(v1.begin() + 1); // 删除第二个元素(7)
// 删除范围
v1.erase(v1.begin(), v1.begin() + 2); // 删除前两个
return 0;
}
insert 与 erase 的时间复杂度:
| 操作位置 | insert | erase |
|---|---|---|
| 尾部 | O(1) | O(1) |
| 中间/头部 | O(n) | O(n) |
五、从数组创建 vector
cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
int arr[] = {1, 2, 3, 4, 5};
// 通过数组创建 vector
vector<int> v1(arr, arr + 5);
// arr → 数组起始地址
// arr + 5 → 数组结束地址(最后一个元素之后)
// 遍历打印
for (vector<int>::iterator it = v1.begin(); it != v1.end(); ++it) {
cout << *it << " ";
}
cout << endl;
return 0;
}
原理 :vector 的构造函数接受两个迭代器参数,[first, last) 左闭右开区间。

第三部分:STL 算法初探
一、for_each 算法
for_each 是 STL 中最常用的遍历算法,对区间内的每个元素执行指定操作。
cpp
#include <iostream>
#include <vector>
#include <algorithm> // STL 算法头文件
using namespace std;
// 普通函数作为操作
void show(int item) {
cout << item << " ";
}
int main() {
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
// 方式1:传入函数指针
for_each(v1.begin(), v1.end(), show);
cout << endl;
// 方式2:传入 Lambda 表达式(C++11)
for_each(v1.begin(), v1.end(),
[](int item) {
cout << item << " ";
}
);
cout << endl;
return 0;
}
for_each 的三要素:
| 参数 | 说明 |
|---|---|
v1.begin() |
起始迭代器 |
v1.end() |
结束迭代器 |
show / lambda |
对每个元素执行的操作 |
二、vector 的构造与拷贝
cpp
#include <vector>
using namespace std;
int main() {
vector<int> v1 = {1, 2, 3, 4, 5};
// 多种拷贝构造方式
vector<int> v2 = v1; // 拷贝构造
vector<int> v3(v1); // 拷贝构造
vector<int> v4(v1.begin(), v1.end()); // 迭代器区间构造
vector<int> v5(v1.begin(), v1.begin() + 3); // 部分拷贝
return 0;
}
第四部分:vector 使用要点
一、常用成员函数速查表
| 函数 | 功能 | 时间复杂度 |
|---|---|---|
push_back(val) |
尾部插入 | O(1) 均摊 |
pop_back() |
尾部删除 | O(1) |
insert(pos, val) |
指定位置插入 | O(n) |
erase(pos) |
删除指定位置 | O(n) |
clear() |
清空所有元素 | O(n) |
size() |
元素个数 | O(1) |
capacity() |
当前容量 | O(1) |
empty() |
判空 | O(1) |
front() |
第一个元素 | O(1) |
back() |
最后一个元素 | O(1) |
at(i) |
带越界检查的访问 | O(1) |
operator[](i) |
不检查越界的访问 | O(1) |
reserve(n) |
预留容量 | O(n) |
shrink_to_fit() |
收缩到合适容量 | O(n) |
二、vector 扩容机制
cpp
vector<int> v;
v.reserve(100); // 提前预留 100 个元素的空间,避免频繁扩容
for (int i = 0; i < 100; i++) {
v.push_back(i); // 这些操作不会触发扩容
}
扩容建议:
-
如果预知元素数量,使用
reserve()提前分配 -
扩容倍数通常是 1.5 或 2,具体取决于编译器实现
三、vector vs 数组
| 对比项 | 原生数组 | vector |
|---|---|---|
| 大小 | 固定 | 动态调整 |
| 越界检查 | 无 | at() 有检查 |
| 拷贝 | 需要手动 memcpy | 直接赋值 |
| 内存管理 | 手动 | 自动 |
| 与 STL 算法配合 | 需要包装 | 天然支持 |
总结
一、字符串流要点
| 要点 | 说明 |
|---|---|
istrstream |
从字符数组读取 |
ostrstream |
向字符数组写入 |
seekg/tellg |
读指针定位 |
seekp/tellp |
写指针定位 |
| 现代替代 | stringstream(<sstream>) |
二、vector 核心要点

三、一句话记忆
vector 是会自动扩容的数组,用 push_back 在尾巴加东西,用迭代器从头到尾遍历,用 for_each 对每个元素执行操作。