GESP C++四级官方考试大纲中,共有11条考点,本文针对第2条考点进行分析介绍。
(2)掌握 C++结构体、二维及多维数组的基本概念及使用
四级其他考点回顾:
【GESP】C++四级考试大纲知识点梳理, (1) 指针
一、结构体(struct
)基础知识
1.1 概念与定义
结构体是 C++ 提供的一种用户自定义复合数据类型,它允许将不同类型的变量组合成一个逻辑整体。
C++ 的结构体(struct
)继承自 C 语言,其核心设计思想是数据聚合 (Data Aggregation)。
- 封装“相关”数据:在程序设计中,总有一些数据是天然相关的,例如一个人的“姓名”和“年龄”。
struct
的初衷就是提供一种机制,将这些逻辑上属于一个整体的数据打包在一起,形成一个自定义的数据单元。这极大地增强了代码的可读性和可维护性。你不必再面对一堆零散的变量,而是操作一个有明确意义的整体。 - 面向对象编程的基石:在 C++ 中,
struct
的能力被大大增强,它和 class
的唯一区别就在于默认访问权限 (struct
默认是 public
,class
默认是 private
)。这使得 struct
成为了实现面向对象编程(OOP)中“类”的另一种方式。它体现了封装 (Encapsulation) 的思想,即将数据和操作数据的方法(成员函数)捆绑在一起。虽然实践中更常使用 class
来表达复杂的对象,但 struct
在表示纯数据集合(Plain Old Data, POD)或小型对象时仍然非常流行。
1.2 定义结构体基本语法格式
1
2
3
4
5
| struct 结构体名 {
成员类型1 成员名1;
成员类型2 成员名2;
...
};
|
🔍 示例:
1
2
3
4
5
| struct Student {
std::string name; // 学生姓名
int age; // 学生年龄
float score; // 学生成绩
};
|
✏️ 说明:
struct
是关键字,表示“结构体”。- 大括号
{}
中定义的是结构体的成员变量。 - 每个成员变量后面以
;
结尾。 - 最后一行的大括号也要有分号
;
结尾!这是很多初学者常犯的错误。
1.3 定义结构体变量的方式
结构体定义后,通常有三种方式定义变量:
✅ 方法 1:先定义结构体,再单独定义变量
1
2
3
4
5
6
7
| struct Student {
std::string name;
int age;
float score;
};
Student s1; // 定义变量
|
✅ 方法 2:定义结构体的同时定义变量
1
2
3
4
5
| struct Student {
std::string name;
int age;
float score;
} s2, s3; // 同时定义了两个变量 s2 和 s3
|
✅ 方法 3:使用 typedef 或 using 创建别名(常见于 C)
1
2
3
4
5
6
7
| typedef struct {
std::string name;
int age;
float score;
} Student;
Student s4;
|
在 C++11 之后,还可以使用 using
关键字代替 typedef
:
1
2
3
4
5
| using Student = struct {
std::string name;
int age;
float score;
};
|
1.4 结构体初始化的几种方式
1.4.1 列表初始化(推荐)
1
| Student s2 = {"Bob", 19, 85.0};
|
- 这是列表初始化(aggregate initialization)的方式。
- C++ 支持结构体的顺序初始化:初始化顺序必须与结构体中成员的声明顺序一致。
- 如果使用 C++11 及以上,也可以使用统一初始化风格:
1.4.2 C++11 统一初始化(推荐)
1
| Student s3{"Carol", 21, 88.0}; // C++11 统一初始化
|
1.4.3 成员赋值初始化(逐一赋值)
1
2
3
4
| Student s1;
s1.name = "Alice";
s1.age = 20;
s1.score = 92.5;
|
- 这是通过结构体类型
Student
定义一个变量 s1
。 - 每个成员变量通过点操作符(
.
)访问并赋值。 - 内部的
name
是 std::string
类型,具有构造函数,s1.name = "Alice";
实际是调用 std::string::operator=
。 - 这是逐成员赋值的方式,便于代码逐步构造结构体对象,适合需要动态赋值的场景(如用户输入)。
1.5 其他结构体使用方式
1.5.1 结构体数组
1
2
3
4
5
| Student students[3] = {
{"Alice", 20, 92.5},
{"Bob", 19, 85.0},
{"Carol", 21, 88.0}
};
|
- 声明一个
Student
类型的数组,长度为 3,每个元素是一个结构体。 - 数组中每个元素都是独立的结构体变量,可以单独访问和修改:
1
| students[1].score = 90.0; // 修改 Bob 的成绩
|
- 使用结构体数组是管理批量实体数据最常见的做法,适用于班级管理、商品库存、客户列表等。
1.5.2 结构体嵌套结构体
1
2
3
4
5
6
7
8
9
10
| struct Course {
std::string name;
float score;
};
struct Student {
std::string name;
int age;
Course math;
};
|
Student
结构体中的 math
是一个 Course
类型的结构体成员,也就是结构体中包含另一个结构体。- 表达了更复杂的数据模型:一个学生不仅有基本信息,还有某门课程的详细信息。
- 使用方式如下:
1
2
3
4
5
| Student s4;
s4.name = "David";
s4.age = 22;
s4.math.name = "Math";
s4.math.score = 95.0;
|
- 这种“结构体嵌套结构体”的方式用于描述多层次关系的数据对象,是面向对象编程的基础雏形。
- 可继续嵌套更深,例如:
1
2
3
4
| struct School {
std::string name;
Student students[100];
};
|
形成一种树状或层级式的数据模型。
1.6 定义结构体时的注意事项⚠️
注意点 | 说明 |
---|
要以分号 ; 结束结构体定义 | 常见语法错误 |
初始化顺序必须一致 | 使用列表初始化时 |
成员名不能重复 | 同一结构体内的变量名必须唯一 |
建议与 class 区分用途 | struct 用于数据模型,class 用于封装行为 |
可以定义不同类型成员 | 如 int 、float 、string 可混合 |
可以嵌套结构体 | 支持成员为另一个结构体类型 |
可以带函数成员 | C++中结构体和类几乎一样,可以定义函数成员 |
默认访问权限是 public | 与类相反,类默认是 private |
1.7 底层原理
struct
的底层原理核心是内存布局 (Memory Layout)。
- 连续内存:在内存中,一个结构体变量的各个成员通常是按其声明顺序连续存放的。例如,
struct Point { int x; int y; };
,一个 Point
变量在内存中就是一个整数 x
紧跟着一个整数 y
。 - 内存对齐 (Memory Alignment):为了提高 CPU 的访问效率,编译器会对结构体成员进行内存对齐。这意味着成员的起始地址会是其自身大小的整数倍。例如,一个
int
(通常4字节)会被放置在能被4整除的内存地址上。这可能导致成员之间出现一些未使用的“填充字节”(Padding)。
示例:
1
2
3
4
5
6
7
| struct Example {
char a; // 1 byte
// 3 bytes padding
int b; // 4 bytes
char c; // 1 byte
// 7 bytes padding
};
|
这个 Example
结构体的大小可能不是 1+4+1=6
字节,而很可能是 16
字节(在64位系统上,通常按最大成员大小或8字节对齐)。了解内存对齐对于进行底层编程、性能优化和与硬件交互非常重要。
遵循“内存对齐”原则关键点如下:
- 成员变量按声明顺序依次排布
- 每个成员地址需对齐到类型字节大小的整数倍
- 整个结构体大小为最大对齐单位的倍数
1.8 结构体小结
结构体是 C++ 中最基础也最常用的数据建模工具之一,使用它可以:
- 聚合多个相关的数据成员
- 实现对现实世界实体的模拟
- 构建更复杂的数据结构(如嵌套结构体、结构体数组)
- 为后续类和对象的学习打下坚实基础
二、C++ 中的二维及多维数组的基本概念及使用
在编程中,数据往往不是简单的线性结构,例如图像是由像素点组成的矩阵、地图是由二维坐标构成的网格、表格是由行和列构成的数据单元。二维与多维数组正是为了解决这类问题而设计的。
2.1 设计定位与应用场景
2.1.1 一维数组的不足
- 一维数组只能表示线性结构,如:一组成绩、一行文本。
- 当需要表示表格、矩阵、棋盘、图像等结构时,一维数组显得无力。
2.1.2 二维/多维数组的设计目的
🌟 用于模拟更高维度的结构化数据,如表格、矩阵、立体网格等。
📌 典型应用场景:
场景 | 示例 |
---|
表格存储 | 学生成绩表、工资表 |
图像处理 | 灰度图、彩色图像(3D 数组) |
棋盘类游戏 | 棋盘状态表示(如五子棋) |
数学计算 | 矩阵、张量运算 |
地图/路径算法 | 网格地图、路径搜索 |
2.2 二维数组的定义与使用
2.2.1 基本语法
1
| type arrayName[行数][列数];
|
这实际上是一个「数组的数组」结构 —— 也就是说,每一行本身就是一个一维数组。
✅ 声明示例:
我们先定义一个 3 行 4 列的数组,名字为 matrix
:
1
2
3
4
5
| int matrix[3][4] = {
{10, 11, 12, 13},
{20, 21, 22, 23},
{30, 31, 32, 33}
};
|
可视化为一个表格结构:
行号 | 列0 | 列1 | 列2 | 列3 |
---|
0 | 10 | 11 | 12 | 13 |
1 | 20 | 21 | 22 | 23 |
2 | 30 | 31 | 32 | 33 |
2.2.2 二维数组初始化的几个例子
二维数组的初始化方法多种多样,下面按常见方式分类介绍:
✅ 方法 1:完全初始化(显式给出所有元素)
1
2
3
4
| int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
|
🧾 说明:
2
表示行数,3
表示列数- 每一行是一个一维数组
- 所有值都显式提供
📦 内存布局:
1
2
3
4
5
6
| matrix[0][0] = 1
matrix[0][1] = 2
matrix[0][2] = 3
matrix[1][0] = 4
matrix[1][1] = 5
matrix[1][2] = 6
|
✅ 方法 2:部分初始化(未写的元素补 0)
1
2
3
4
| int matrix[2][3] = {
{1}, // 第1行只有1个值,其余自动补0
{4, 5} // 第2行给出2个值,第3个补0
};
|
🧾 结果:
1
2
| matrix[0] = {1, 0, 0}
matrix[1] = {4, 5, 0}
|
✅ 方法 3:一维方式初始化(扁平写法)
1
| int matrix[2][3] = {1, 2, 3, 4, 5, 6};
|
相当于:
1
2
3
4
| int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
|
📌 原理:
- 元素按行优先顺序自动填充
- 推荐在数据来源是线性数据时使用
✅ 方法 4:默认初始化(不写初始值)
1
| int matrix[2][3] = {}; // 全部元素初始化为 0
|
⚠️ 注意:只适用于 POD(Plain Old Data)类型,如 int
、char
、float
等。
✅ 方法 5:动态推导行数(省略第一维)
1
2
3
4
| int matrix[][3] = {
{1, 2, 3},
{4, 5, 6}
};
|
📌 说明:
- 第一维(行数)由编译器自动推导
- 第二维(列数)必须显式给出
✅ 方法 6:使用 memset
初始化为 0
1
2
| int matrix[3][4];
std::memset(matrix, 0, sizeof(matrix)); // 全部清零
|
📌 memset
适用于设置为 0 的情况,不适合非0值或非基本类型。
✅ 方法 7:使用循环初始化(适用于非简单规律)
1
2
3
4
5
6
7
| int matrix[3][3];
int value = 1;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
matrix[i][j] = value++;
}
}
|
结果:
1
2
3
4
| matrix =
1 2 3
4 5 6
7 8 9
|
2.2.3 访问二维数组的几个例子
🌟 示例 1:访问第 2 行第 3 列的值
1
2
| int x = matrix[1][2];
std::cout << "matrix[1][2] = " << x << std::endl;
|
解释:
[1][2]
:第 2 行(从 0 开始计数),第 3 列- 值为
22
🌟 示例 2:访问第一行的所有元素
1
2
3
| for (int j = 0; j < 4; j++) {
std::cout << matrix[0][j] << " ";
}
|
输出:
解释:
🌟 示例 3:访问所有列的第 3 行
1
2
3
| for (int j = 0; j < 4; j++) {
std::cout << matrix[2][j] << " ";
}
|
输出:
🌟 示例 4:访问主对角线元素(下标 i == j)
1
2
3
| for (int i = 0; i < 3; i++) {
std::cout << matrix[i][i] << " ";
}
|
输出:
解释:
- 主对角线:matrix[0][0]、matrix[1][1]、matrix[2][2]
2.2.4 修改二维数组的值:几个典型操作
🔄 示例 1:将第 3 行第 1 列的值改为 100
修改前:matrix[2][0] = 30 修改后:matrix[2][0] = 100
🔄 示例 2:将所有值加 1
1
2
3
4
5
| for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
matrix[i][j] += 1;
}
}
|
作用:
- 将每个元素自增 1
matrix[0][0]
变为 11
,以此类推
🔄 示例 3:将所有偶数变为 0
1
2
3
4
5
6
| for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
if (matrix[i][j] % 2 == 0)
matrix[i][j] = 0;
}
}
|
2.2.5 二维数组的内存线性结构
二维数组在内存中是连续的一维结构,按「行优先顺序」排列。
1
2
| matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
matrix[1][0], matrix[1][1], ..., matrix[2][3]
|
所以 matrix[1][2]
实际在内存中的位置是第 1×4 + 2 = 6
个元素(假设从 matrix[0][0]
起始)
🧮 二维数组的地址计算公式
对于数组 int a[m][n]
,元素 a[i][j]
在内存中的偏移位置为:
1
| 地址 = 基地址 + (i * n + j) * sizeof(int)
|
说明:
n
为列数sizeof(int)
是一个元素的字节大小- C++ 使用线性内存连续展开所有元素
2.2.6 总结
操作类型 | 示例 | 含义 |
---|
访问 | matrix[1][2] | 第2行第3列的值(22) |
修改 | matrix[2][0] = 100; | 将第3行第1列设为100 |
遍历 | 双重循环 | 遍历整个二维数组 |
条件操作 | 通过if 判断 | 可实现筛选或批量修改 |
2.3 三维及多维数组的定义与使用
2.3.1 三维数组语法
1
| type arrayName[depth][row][col];
|
示例:三维数组:
1
2
3
4
5
6
7
8
9
10
11
12
| int cube[2][3][4] = {
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
},
{
{13, 14, 15, 16},
{17, 18, 19, 20},
{21, 22, 23, 24}
}
};
|
- 结构上可理解为:2 个矩阵,每个矩阵有 3 行 4 列
- 可用于模拟立体结构,如 3D 空间、视频帧序列等
2.3.2 三维数组的初始化
三维数组结构可以理解为: int arr[x][y][z];
→ 表示有 x
个二维数组,每个二维数组有 y
行 z
列。
✅ 方法 1:完整初始化
1
2
3
4
5
6
7
8
9
10
| int arr[2][2][3] = {
{
{1, 2, 3},
{4, 5, 6}
},
{
{7, 8, 9},
{10, 11, 12}
}
};
|
🔍 结构解析:
arr[0]
是第一个 2×3 的矩阵 arr[1]
是第二个 2×3 的矩阵
可以这样可视化:
1
2
3
4
5
6
7
| arr[0]:
[1, 2, 3]
[4, 5, 6]
arr[1]:
[7, 8, 9]
[10, 11, 12]
|
✅ 方法 2:部分初始化(其余补0)
1
2
3
4
5
6
7
8
9
10
| int arr[2][2][3] = {
{
{1}, // 其余 [0][0][1..2] 和 [0][1][0..2] 为 0
{4, 5}
},
{
{7}, // 其余补0
{10}
}
};
|
✅ 方法 3:扁平化初始化
1
2
3
4
| int arr[2][2][3] = {
1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12
};
|
等价于方法1,会按照行优先顺序依次填充每一维。
✅ 方法 4:默认初始化为0
1
| int arr[2][3][4] = {}; // 所有元素初始化为0
|
✅ 方法 5:循环初始化
适合大尺寸数组或有规律赋值:
1
2
3
4
5
6
7
8
9
| int arr[2][2][3];
int val = 1;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 3; k++) {
arr[i][j][k] = val++;
}
}
}
|
输出 arr[i][j][k]
会依次是 1 到 12。
2.3.3 四维及更高维数组初始化
C++ 支持更高维度的数组,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| int arr[2][2][2][2] = {
{
{
{1, 2},
{3, 4}
},
{
{5, 6},
{7, 8}
}
},
{
{
{9, 10},
{11, 12}
},
{
{13, 14},
{15, 16}
}
}
};
|
每一层包裹的是低一维的结构。初始化语法遵循「逐层嵌套」的方式。
2.3.4 多维数组访问
1
| int val = cube[1][2][3]; // 第2块矩阵的第3行第4列的值
|
三维数组遍历示例:
1
2
3
4
5
6
7
8
9
| for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 4; k++) {
std::cout << cube[i][j][k] << " ";
}
std::cout << std::endl;
}
std::cout << "----" << std::endl;
}
|
2.3.5 内存布局原理(多维数组)
多维数组在 C++ 中实际是线性存储,按照 行优先(row-major order) 的顺序展开。
例如:
1
| int arr[2][2][3]; // 实际是一个连续的 int[12]
|
在内存中按如下顺序排列:
1
2
3
| arr[0][0][0], arr[0][0][1], arr[0][0][2],
arr[0][1][0], arr[0][1][1], arr[0][1][2],
arr[1][0][0], ..., arr[1][1][2]
|
因此你可以用一维指针连续遍历整个数组:
1
2
3
4
| int* p = &arr[0][0][0];
for (int i = 0; i < 12; i++) {
std::cout << *(p + i) << " ";
}
|
三、【拓展】二维数组与指针的关系
3.1 二维数组与指针变量关系举例
示例 1:用指针访问二维数组元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| #include <iostream>
using namespace std;
int main() {
int a[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
int* p = &a[0][0]; // p 指向二维数组首地址(整块内存)
for (int i = 0; i < 6; i++) {
cout << *(p + i) << " ";
}
return 0;
}
|
💡 解释:
a
是二维数组,&a[0][0]
是首个元素地址- 将地址赋给
int*
,可以按一维方式访问整个内存区域
示例 2:使用指针访问二维数组行
1
2
3
| int (*p)[3] = a; // p 是一个指针,指向含有3个int元素的数组
cout << p[1][2]; // 输出第2行第3列的值:6
|
💡 解释:
int (*p)[3]
表示:p
是指向含有3个整数的一维数组的指针p[1][2]
相当于 a[1][2]
示例 3:函数中使用指针接收二维数组参数
1
2
3
4
5
6
7
8
| void print(int (*p)[3], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) {
cout << p[i][j] << " ";
}
cout << endl;
}
}
|
调用方法:
1
2
| int a[2][3] = { {1,2,3},{4,5,6} };
print(a, 2);
|
💡 解释:
- 函数参数
int (*p)[3]
接收的是指向一维数组的指针 - 保证列数固定(否则编译器无法解析内存偏移)
示例 4:强制转换为 int*
指针访问二维数组
1
2
3
4
5
6
7
8
| int a[2][3] = {
{1, 2, 3}, {4, 5, 6}
};
int* p = (int*)a;
for (int i = 0; i < 6; i++) {
cout << *(p + i) << " ";
}
|
⚠️ 适合只想线性访问所有元素的场景,不推荐用于跨函数传递。
3.2 图解指针与二维数组的关系
假设数组:
1
2
3
4
| int a[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
|
元素 | 地址 |
---|
a[0][0] | &a[0][0] |
a[0][1] | &a[0][0] + 1 |
a[1][0] | &a[0][0] + 3 |
a[1][2] | &a[0][0] + 5 |
即 a
本质上是一块 int[6]
的线性内存,二维结构只是一种语义化的访问方式。
3.3 总结知识点
表达式 | 含义 |
---|
a | 指向 a[0] 的指针,类型为 int (*)[3] |
*a / a[0] | 指向 a[0][0] 的地址,类型为 int* |
a[i][j] | 实际是 *(*(a + i) + j) |
int* p = &a[0][0] | 将二维数组线性化访问 |
int (*p)[3] = a | 指向一行的指针,用于逐行访问或传参 |
四、使用数组的注意事项
问题 | 说明 |
---|
数组越界 | 无越界保护,访问非法内存 |
数组大小必须编译期常量(C++98/03) | C++11 起可用动态数组或 std::vector 替代 |
大数组不建议定义在栈上 | 栈空间有限,建议使用堆内存或动态分配 |
三维以上数组管理困难 | 建议封装类或使用 STL 容器 |
五、现代 C++ 替代方案:std::vector
在现代 C++ 中,std::vector
是二维及多维数组的推荐替代方案,它更安全、更灵活,适用于动态大小和复杂操作的数组场景。
5.1 为什么选择 std::vector
代替原生数组?
优点 | 说明 |
---|
✅ 动态大小 | vector 支持运行时动态扩展,适应不确定维度或大小变化的需求 |
✅ 内存安全 | 自动管理内存,避免缓冲区溢出或手动 new/delete 错误 |
✅ 丰富功能 | 提供 .size() 、.push_back() 、.resize() 等便捷方法 |
✅ 容易嵌套 | 可以定义 vector<vector<T>> 实现二维/多维数组 |
✅ 与标准库兼容性好 | 支持与 STL 算法、迭代器、范围 for 循环无缝配合 |
5.2 一维 std::vector
使用方式
下面是 C++ 中 std::vector
的定义语法规则及其结构要素说明。
5.2.1 std::vector
定义的语法规则
或者:
1
| std::vector<类型> 变量名(元素个数);
|
或者:
1
| std::vector<类型> 变量名(元素个数, 初始值);
|
或者:
1
| std::vector<类型> 变量名 = {初始值1, 初始值2, ...};
|
头文件: 使用前必须包含头文件 #include <vector>
5.2.2 定义构成要素说明
语法元素 | 说明 |
---|
std::vector | 标准模板库中的动态数组容器名称 |
<类型> | 存储的数据类型,如 int 、double 、std::string 等 |
变量名 | 向量变量的名称 |
(元素个数) | 创建一个指定长度的向量,每个元素默认初始化 |
(元素个数, 初始值) | 创建一个指定长度的向量,每个元素都设置为给定值 |
= {列表} | 使用初始化列表直接赋初值(C++11 起支持) |
5.2.3 定义代码示例
1. 定义一个空的 int 类型 vector
2. 定义一个长度为 5,元素默认值为 0 的 vector
3. 定义一个长度为 4,所有元素初始值为 100 的 vector
1
| std::vector<int> v(4, 100);
|
4. 使用初始化列表方式定义(推荐方式)
1
| std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
|
5. 嵌套定义二维 vector
1
| std::vector<std::vector<int>> matrix(3, std::vector<int>(4, 0));
|
小贴士
- 类型可为任意可复制对象:不仅限于基本类型,也可以是结构体或类。
- 推荐使用初始化列表(C++11 起):代码更简洁直观。
- vector 可随时扩展/收缩:无需提前固定长度,适合动态数据场景。
- 访问元素推荐使用
.at(i)
:具备越界检查功能,调试更安全。
5.2.4 添加和删除元素
1
2
3
4
5
6
7
| std::vector<int> v;
v.push_back(10); // 在末尾添加元素
v.push_back(20);
v.push_back(30);
v.pop_back(); // 删除最后一个元素
|
5.2.5 访问元素
1
2
3
4
| std::vector<int> v = {1, 2, 3};
std::cout << v[0]; // 不做边界检查,速度快
std::cout << v.at(1); // 做边界检查,越界会抛出异常
|
5.2.6 遍历 vector
方法 1:传统 for 循环
1
2
| for (size_t i = 0; i < v.size(); ++i)
std::cout << v[i] << " ";
|
方法 2:范围 for 循环(C++11+)
1
2
| for (int x : v)
std::cout << x << " ";
|
方法 3:使用迭代器
1
2
| for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it)
std::cout << *it << " ";
|
5.2.7 修改元素
5.2.8 常用函数汇总
函数名 | 说明 |
---|
.size() | 返回当前元素个数 |
.empty() | 判断是否为空 |
.clear() | 清空所有元素 |
.resize(n) | 调整大小(截断或填充默认值) |
.front() | 获取第一个元素 |
.back() | 获取最后一个元素 |
.insert(pos, val) | 在指定位置插入元素 |
.erase(pos) | 删除指定位置元素 |
.swap(v2) | 与另一个 vector 交换内容 |
完整示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| #include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> nums = {10, 20, 30};
nums.push_back(40); // 添加元素
nums[1] = 25; // 修改第二个元素
nums.erase(nums.begin()); // 删除第一个元素
cout << "当前 vector 内容:" << endl;
for (int val : nums) {
cout << val << " ";
}
cout << endl;
cout << "长度: " << nums.size() << ", 第一个元素: " << nums.front() << ", 最后一个元素: " << nums.back() << endl;
return 0;
}
|
输出:
1
2
3
| 当前 vector 内容:
25 30 40
长度: 3, 第一个元素: 25, 最后一个元素: 40
|
5.3 二维 std::vector
使用方式
✅ 1. 定义和初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| #include <iostream>
#include <vector>
using namespace std;
int main() {
// 定义一个 3x4 的二维 vector,并初始化为 0
vector<vector<int>> matrix(3, vector<int>(4, 0));
// 修改元素
matrix[1][2] = 5;
// 输出
for (const auto& row : matrix) {
for (int val : row) {
cout << val << " ";
}
cout << endl;
}
return 0;
}
|
🔍 说明:
vector<vector<int>> matrix(3, vector<int>(4, 0))
→ 表示有 3 行,每行是一个含 4 个元素值为 0 的 vector<int>
✅ 2. 动态构建二维数组
适合数据来自用户输入或文件等情况:
1
2
3
4
5
6
7
| int rows, cols;
cin >> rows >> cols;
vector<vector<int>> mat(rows, vector<int>(cols));
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
cin >> mat[i][j];
|
✅ 3. 不规则二维数组(Jagged array)
1
2
3
4
5
| vector<vector<int>> jagged = {
{1, 2, 3},
{4, 5},
{6}
};
|
每一行可以有不同长度,这是原生 C++ 数组难以做到的。
✅ 4. 使用迭代器/范围 for 循环访问
1
2
3
4
5
6
| for (auto& row : jagged) {
for (int val : row) {
cout << val << " ";
}
cout << endl;
}
|
5.4 三维 std::vector
使用方式
1
2
3
4
5
| // 2 × 3 × 4 的三维数组,初始化为 0
vector<vector<vector<int>>> arr(2, vector<vector<int>>(3, vector<int>(4, 0)));
// 修改元素
arr[1][2][3] = 99;
|
5.5 std::vertor 性能和底层原理补充
vector
底层使用 动态数组,通过 new
动态分配内存。- 自动扩容机制采用「按比例增长」(如 1.5~2 倍)策略以减少频繁 realloc。
- 每个
vector
独立维护数据和容量,因此 vector<vector<T>>
在物理上并不连续(适合灵活访问,不适合频繁跨行大规模遍历)。
所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code
GESP各级别考纲要点、知识拓展和练习题目清单详见C++学习项目主页
“luogu-”系列题目已加入洛谷Java、C++初学团队,作业清单,可在线评测,团队名额有限,欢迎加入。
“bcqm-”系列题目可在编程启蒙题库进行在线评测。