文章

【GESP】C++四级考试大纲知识点梳理, (2) 结构体和二维数组

GESP C++四级官方考试大纲中,共有11条考点,本文针对第2条考点进行分析介绍。

(2)掌握 C++结构体、二维及多维数组的基本概念及使用

四级其他考点回顾:

【GESP】C++四级考试大纲知识点梳理, (1) 指针


一、结构体(struct)基础知识

1.1 概念与定义

结构体是 C++ 提供的一种用户自定义复合数据类型,它允许将不同类型的变量组合成一个逻辑整体。

C++ 的结构体(struct)继承自 C 语言,其核心设计思想是数据聚合 (Data Aggregation)

  • 封装“相关”数据:在程序设计中,总有一些数据是天然相关的,例如一个人的“姓名”和“年龄”。struct 的初衷就是提供一种机制,将这些逻辑上属于一个整体的数据打包在一起,形成一个自定义的数据单元。这极大地增强了代码的可读性和可维护性。你不必再面对一堆零散的变量,而是操作一个有明确意义的整体。
  • 面向对象编程的基石:在 C++ 中,struct 的能力被大大增强,它和 class 的唯一区别就在于默认访问权限 (struct 默认是 publicclass 默认是 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
  • 每个成员变量通过点操作符(.)访问并赋值。
  • 内部的 namestd::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 用于封装行为
可以定义不同类型成员intfloatstring 可混合
可以嵌套结构体支持成员为另一个结构体类型
可以带函数成员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
010111213
120212223
230313233

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)类型,如 intcharfloat 等。


✅ 方法 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] << " ";
}

输出:

1
10 11 12 13

解释:

  • 外部索引是行号(固定为 0)
  • 内部循环遍历列

🌟 示例 3:访问所有列的第 3 行
1
2
3
for (int j = 0; j < 4; j++) {
    std::cout << matrix[2][j] << " ";
}

输出:

1
30 31 32 33

🌟 示例 4:访问主对角线元素(下标 i == j)
1
2
3
for (int i = 0; i < 3; i++) {
    std::cout << matrix[i][i] << " ";
}

输出:

1
10 21 32

解释:

  • 主对角线:matrix[0][0]、matrix[1][1]、matrix[2][2]

2.2.4 修改二维数组的值:几个典型操作

🔄 示例 1:将第 3 行第 1 列的值改为 100
1
matrix[2][0] = 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 个二维数组,每个二维数组有 yz 列。

✅ 方法 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
std::vector<类型> 变量名 = {初始值1, 初始值2, ...};

头文件: 使用前必须包含头文件 #include <vector>


5.2.2 定义构成要素说明

语法元素说明
std::vector标准模板库中的动态数组容器名称
<类型>存储的数据类型,如 intdoublestd::string
变量名向量变量的名称
(元素个数)创建一个指定长度的向量,每个元素默认初始化
(元素个数, 初始值)创建一个指定长度的向量,每个元素都设置为给定值
= {列表}使用初始化列表直接赋初值(C++11 起支持)

5.2.3 定义代码示例

1. 定义一个空的 int 类型 vector
1
std::vector<int> v;
2. 定义一个长度为 5,元素默认值为 0 的 vector
1
std::vector<int> v(5);
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 修改元素

1
v[1] = 100;

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-”系列题目可在编程启蒙题库进行在线评测。

本文由作者按照 CC BY 4.0 进行授权