封面: C++实现动态二维数组的两种简易方法

C++实现动态二维数组的两种简易方法

ZL Asica2021-10-28

当无法使用静态分配的数组时 — 因为你在编译时不知道合适的大小,或该数组太大而无法合理地放入运行时堆栈,或该数组的生命周期比创建它的函数更长。动态分配数组涉及到使用new运算符,类似于其他对象的动态分配,不同之处在于数组需要我们另外指定大小。

动态分配数组是使用new表达式完成的,该表达式会动态分配足够的内存来存储整个数组,然后返回指向数组第一个单元格的指针。

CPP
1int* a = new int[10];

表达式 new int[10] 在堆上分配一个足够大的内存块来存储 10 个整数,并返回一个指向第一个的指针。第二个的位置直接跟在第一个之后,第三个直接跟在第二个之后,依此类推,所有的单元格都是相同的类型。所以给定一个指向第一个单元格的指针和一个索引,在幕后,可以使用以下计算来计算任何给定单元格的索引:

CPP
1单元格 i 的地址 = (单元格 0 的地址) + (sizeof(int) * i)

注意,计算具有大索引的单元格的地址并不比使用小索引更消耗性能。这个计算只是一个乘法和加法;如果我们假设给定地址的内存访问需要恒定时间,那么访问数组中的任何单元都需要恒定时间。(在实践中,内存访问时间可能会因缓存等影响而有所不同,尽管你可以合理地认为主内存访问花费恒定时间。)

有趣的是,返回的指针类型并未指定有关数组的任何内容。当我们动态分配一个int数组时,我们得到的是一个int*,即一个指向int的指针。数组在一般情况下,实现为指针,以他们的第一个单元,它是由我们来了解是否特定int*指向一个单一的int或int数组。

一旦有了指向数组的指针,就可以像访问静态分配的数组一样访问它的每一个数字:

CPP
1int* a = new int[10]; 2a[3] = 4; 3std::cout << a[3] << std::endl;

a[3]相当于假想表达*q,其中q是一个指向int占用三个单位的一个点。换句话说,a[3]给你提供的是这个单元格中的int(从理论上讲,是对它的引用),而不是指向这个单元格的指针。

当完成动态分配的数组时,需要释放它,就像您处理任何其他动态分配的对象一样。但是,重要的是要注意你要使用不同的运算符delete[]来执行此操作。像delete一样,你给delete[]一个指向数组的指针,它会为你释放整个数组(以及它所有单元格中的所有对象)。

CPP
1delete[] a;

由你决定哪些指针指向数组,并在需要时使用delete[]。在指向数组的指针上使用delete而不是delete[ ],或在指向单个值的指针上使用delete[]而不是delete,会导致“undefined behavior”。就像我们之前看到的使用delete一样,指针a不受影响,尽管它现在指向未分配的内存,因此它现在就不会被再使用。

动态二维数组的分配

CPP
1int** test = new int*[rows]; 2 for(int i = 0; i < rows; i++) 3 test[i] = new int[columns];

释放动态分配二维数组占用的空间

CPP
1for(int i = 0; i < rows; i++) 2 delete []test[i]; 3 delete []test;

注意使用这种方法你需要在文件头

CPP
1#include <vector>

使用vector动态分配二维数组

CPP
1std::vector<std::vector<int>> test(rows); 2 for (i = 0; i < test.size(); i++) 3 test[i].resize(columns);

使用swap()方法清空vector占用的内存空间

CPP
1// vector的clear方法无法清空其占用的内存 2//可以使用swap来使一个空的vector来替换掉原来test里有的内容。 3vector<T>().swap(test);
Creative Commons Logo

本文作者:ZL Asica

本文标题:C++实现动态二维数组的两种简易方法

本文链接:https://www.zla.pub/cpp-2d-dynamical-array

本文采用 CC BY-SA 4.0 Deed 进行许可