C++ STL vector 动态数组 —— 可以自动变长的大箱子
中等34C++ STL 里的 vector:会自动长大的“零食箱”
你有没有遇到过这种情况:去超市买零食,不知道要买多少包,于是拿了一个小袋子,结果越装越多,袋子都快撑破了。要是有一个“会自动变大的袋子”就好了!C++ 里的 vector 就是这样一个聪明的“箱子”——它会根据你放进去的东西数量,自动变大,装下所有数据。它和普通数组最大的区别是:普通数组的大小是固定的(比如 int a[10] 永远只能装 10 个数),而 vector 可以随时往里加东西,它会自己扩大容量,完全不让你操心内存够不够用。
1. 怎么得到一个“箱子”?
要使用 vector,第一步是告诉 C++:“嘿,我要用这个智能箱子!” 方法就是加上一句:
#include <vector> // 这是 vector 的“使用说明书”
然后,你就可以用这样的格式创建一个箱子:
vector<你想装的东西的类型> 箱子的名字;
比如,你想装全班同学的考试成绩(都是整数),就这样写:
vector<int> scores; // 一个空的整数箱子,专门用来装分数
这个 scores 一开始是空的,里面啥也没有,就像你刚买回来的空书包。
生活小例子:你有一个“自动变大”的收纳箱,一开始是扁扁的,放一本书它就撑大一点,放十本书它就变大很多,永远不用担心箱子太小。
2. 往箱子里放东西、拿东西
2.1 在末尾放一个元素:push_back
push_back 就像把一包零食从箱子顶部塞进去。每次塞进去,箱子大小自动 +1。
scores.push_back(95); // 放进去第一个分数 95
scores.push_back(87); // 再放进去 87
scores.push_back(92); // 再放 92
// 现在 scores 里有 3 个分数:95, 87, 92
2.2 拿走最后一个元素:pop_back
如果你后悔了,想拿出最后放进去的那包零食,就用 pop_back。
scores.pop_back(); // 拿走了最后一个 92,现在箱子里只剩 95 和 87
注意:这就像从一叠书上面拿走最上面那本,只能拿最后一本,不能拿中间的。
2.3 看看箱子里有几个元素:size
想数一数箱子里现在有几样东西?用 size() 就好啦,它返回一个整数。
cout << "目前箱子里有 " << scores.size() << " 个分数" << endl;
// 如果之前 push_back 了 3 个又 pop_back 了一个,结果就是 2
2.4 通过“下标”访问任意位置的元素:[ ]
你学过普通数组 a[0] 这种写法吧?vector 也支持同样的方括号下标,下标从 0 开始。
cout << "第一个分数是:" << scores[0] << endl; // 输出 95
cout << "第二个分数是:" << scores[1] << endl; // 输出 87
就像你给箱子里的零食贴上了标签:第 0 号是薯片,第 1 号是巧克力……但记住,不要访问下标 >= size() 的位置,不然就“越界”了,程序会出问题(后面会讲)。
2.5 从头到尾遍历:用 for 循环
你可以像处理普通数组一样,用 for 循环把箱子里的东西都看一遍:
for (int i = 0; i < scores.size(); i++) {
cout << scores[i] << " "; // 依次输出每个分数
}
或者用 C++11 引入的“范围 for 循环”,更简单:
for (int score : scores) {
cout << score << " ";
}
3. 还有更多实用操作
除了上面的,vector 还有很多方便的小工具,下面列出几个最常用的:
| 操作 | 作用 | 生活比喻 |
|---|---|---|
v.clear() | 清空所有元素,箱子变回空的 | 把零食全部倒出来,箱子变回扁扁的 |
v.empty() | 判断箱子是否为空,空则返回 true | 摸一摸箱子,空的就告诉你是空的 |
v.front() | 返回第一个元素 | 拿出最下面的那包薯片看看(但不拿出) |
v.back() | 返回最后一个元素 | 拿出最上面那包巧克力看看 |
v.insert(pos, val) | 在指定位置插入一个值(位置用迭代器) | 把一包饼干插在箱子的第 2 层中间 |
v.erase(pos) | 删除指定位置的元素 | 从中间抽走一包零食 |
注意:
insert和erase的操作会移动元素,就像你从一叠书中间抽走一本,上面的书都往下掉一样,可能会让程序变慢,但不用担心,vector 会帮你处理好。
举一个使用 insert 的例子:
vector<int> numbers;
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30); // 现在是 10, 20, 30
// 想在 20 前面插入 15
numbers.insert(numbers.begin() + 1, 15); // 变成 10, 15, 20, 30
这里的 numbers.begin() 是指向第一个元素的“指针”(叫迭代器),+1 就跳到第二个位置。
4. 新手最容易犯的三个错误
❌ 错误一:滥用 [ ] 访问不存在的元素
vector<int> v; // 空的箱子
v[0] = 5; // ❌ 危险!箱子是空的,没有第 0 个位置
正确做法:要么先用 push_back 放入元素,要么用 resize 设置大小后再用下标。
❌ 错误二:在循环中给 vector 不断增加元素导致“迭代器失效”
比如下面这个循环,想给 scores 每个成绩加 10 分,顺便再加一个新成绩,结果可能会出问题:
for (int i = 0; i < scores.size(); i++) {
scores.push_back(scores[i] + 10); // ❌ 每加一个 size 就变大,循环可能停不下来!
}
教训:不要在遍历 vector 的时候同时使用 push_back 或 pop_back 改变大小,除非你很清楚后果。通常先记下原始长度再用。
❌ 错误三:忘记包含头文件
vector<int> v; // ❌ 没有 #include <vector>,编译器不认识 vector
记得在文件最前面加上 #include <vector>。
5. 完整示例:记录零花钱的出入账
下面这个程序模拟了一周零花钱的记录:你每天存一点、花一点,最后算算还剩多少钱。
#include <iostream>
#include <vector> // 使用 vector 必须包含
using namespace std;
int main() {
vector<int> money; // 创建一个空箱子,用来记录每天的零花钱变化
int total = 0; // 初始总钱数为 0
// 第1天:妈妈给 20 元
money.push_back(20);
// 第2天:买文具花掉 8 元(记作 -8)
money.push_back(-8);
// 第3天:帮邻居跑腿赚了 15 元
money.push_back(15);
// 第4天:买零食花掉 10 元
money.push_back(-10);
// 第5天:爸爸又给了 50 元
money.push_back(50);
cout << "这5天一共有 " << money.size() << " 笔记录" << endl;
// 用循环计算总钱数
for (int i = 0; i < money.size(); i++) {
total = total + money[i]; // 把这天的变化加到 total 上
}
cout << "最后还剩 " << total << " 元" << endl;
// 再模拟一天:捡到 5 元
money.push_back(5);
cout << "现在总共有 " << money.size() << " 笔记录,钱数为:";
total = 0;
for (int m : money) { // 用范围 for 重新计算
total = total + m;
}
cout << total << " 元" << endl;
// 清空记录,准备下一周
money.clear();
cout << "清空后,箱子里有 " << money.size() << " 条记录" << endl;
return 0;
}
运行结果(大概):
这5天一共有 5 笔记录
最后还剩 67 元
现在总共有 6 笔记录,钱数为:72 元
清空后,箱子里有 0 条记录
6. 为什么不用普通数组?
| 对比项 | 普通数组 int a[100] | vector 动态数组 |
|---|---|---|
| 大小 | 固定(比如 100),多了装不下 | 自动变大,塞多少装多少 |
| 尾部添加 | 要自己记录下标,很麻烦 | push_back 一行搞定 |
| 获取长度 | 要自己算(sizeof/int 或额外变量) | size() 直接返回 |
| 灵活性 | 不能直接插入、删除中间元素 | 提供 insert、erase |
所以,只要你不确定数据到底有多少个,或者需要频繁往末尾加东西,就用 vector。它比普通数组更安全、更省心。
7. 还想学更多?
vector 是 C++ STL(标准模板库)中最基础的容器之一。有了 vector 的基础,你可以继续了解:
list(链表):可以快速在中间插入、删除,但访问元素比 vector 慢。deque(双端队列):可以在头部和尾部快速添加/删除。map(映射):像字典一样,通过“键”找到“值”,比如根据学号查成绩。
也可以学习 vector 的一些高级用法,比如二维 vector(装多个箱子的箱子)、用 sort 对 vector 排序等。
总之,vector 是你编程路上最忠诚的伙伴之一——它会自动长大,永远不让你失望。下次写程序需要存一堆东西时,记得先想到它哦!
例题精讲
下列关于C++ STL vector的说法,错误的是?
对于一个空的vector对象,调用reserve(100)后,其size变为100。
下列代码使用vector存储整数,并向其中添加1到10,然后遍历输出。请填写空缺部分。
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v;
for (int i = 1; i <= 10; ++i) {
___(1)___; // 将i添加到v末尾
}
for (int i = 0; i < v.___(2)___; ++i) {
cout << v[i] << " ";
}
return 0;
}下列代码使用迭代器遍历vector<int>,并计算所有元素的和。请填写空缺部分。
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {2, 4, 6, 8, 10};
int sum = 0;
for (auto it = v.___(1)___; it != v.___(2)___; ++it) {
sum += *it;
}
cout << "Sum = " << sum;
return 0;
}已知vector<int> vec = {1, 2, 3, 4, 5},执行以下哪条语句后,vec的size()变为3?