C++ 使用 new 创建二维数组实例
作者:mkckr0
1. 直接创建
C++ 使用 new 创建二维数组最直接的方法就是 new T[M][N]
。返回的指针类型是 T (*)[N]
,它是指向数组的指针,可以直接使用数组下标形式访问元素。释放内存直接使用delete[]
。示例代码:
#include <iostream> class A { public: A() { std::cout << "A::A" << std::endl; } ~A() { std::cout << "A::~A" << std::endl; } int x; }; int main() { A (*p)[3] = new A[2][3]; delete[] p; }
执行结果:
A::A A::A A::A A::A A::A A::A A::~A A::~A A::~A A::~A A::~A A::~A
可以看到 A 的构造函数和析构函数正常执行。如果觉得 T (*)[N]
繁琐,可以直接使用 auto p = new T[M][N]
。三维数组甚至更高维数组都可以使用这种方法。例如,三维数组使用 new T[M][N][O]
进行创建,依旧使用 delete[] p
进行释放。
为什么可以这样写?因为这种多维数组和普通的多维数组都是通过一维数组实现的。例如,int a[6][8]
,实际上编译器会转化为 int b[6 * 8]
一维数组。然后每次访问二维数组 a[i][j]
相当于访问 b[i * 8 + j]
。从二维、三维数组的转化过程中可以发现一些规律。
T a[M][N] --> T b[M * N], a[i][j] --> b[i * N + j] T a[M][N][O] --> T b[M * N * O], b[i][j][k] --> b[i * N * O + j * O + k]
编译器进行下标转换时,并没有用到第 0 维的大小,而其它维的大小都是必须的。这也就是为什么下面代码能正确执行。
int a[2][3]; int (*p)[3] = a;
由于多维数组本质上是一维数组,所以释放内存都是 delete[] p
,而没有奇怪的 delete[][]
语法。
2. 借助指针数组
还有一种方法就是先 new T*[M]
创建一个指针数组,其每个元素保存每一行的首个元素的地址,再使用 new T[N]
创建每一行。示例代码如下:
A** p = new A*[2]; for (int i = 0; i < 2; ++i) { p[i] = new A[3]; } for (int i = 0; i < 2; ++i) { delete[] p[i]; } delete[] p;
这种方法非常繁琐,首先 new T*[M]
不能写成 new (T(*)[M])
,因为它是指针数组而不是数组指针。其次,需要对每一行调用 new T[N]。释放内存时,要先使用 delete[]
释放每一行,再调用 delete[]
释放数组指针。这几个步骤一步都不能错,不然就出现野指针或者内存泄漏。这段代码我也是用 Address Sanitizer 和 Leak Sanitizer 检查一遍才写对。
这种方法唯一的好处就是可以创建交错数组(Jagged Array),也就是每一行的大小不一样。例如:
A **p = new A *[2]; p[0] = new A[3]; p[1] = new A[4]; for (int i = 0; i < 2; ++i) { delete[] p[i]; } delete[] p;
3. 借助 std::vector
可以用 std::vector 对上面这种方法进行包装,使其更加易用。示例代码如下:
std::vector<std::vector<int>> v{ std::vector<int>(3), std::vector<int>(4) }; std::cout << v[0].size() << " " << v[1].size() << std::endl;
这段代码创建了一个二维数组,第 0 行有 3 个元素,第 1 行有 4 个元素。这种方法既能创建交错数组,也不需要手动释放内存。
到此这篇关于C++ 使用 new 创建二维数组实例的文章就介绍到这了,更多相关C++ 使用 new 创建二维数组内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!