64 C++多维数组
今天讲的是多维数组,请务必了解31 Arrays in C++和16 POINTERS in C++,因为处理任何类型的数组时,指针都是非常重要的(因为数组就是内存块,处理内存的简单方法就是使用指针)
1. 多维数组与常规数组的不同之处
从二维数组开始作为一个例子,实际上它只是数组的数组(三维数组就是数组的数组的数组.....),就是数组的集合。 我们考虑处理数组的一种策略就是使用指针,我们有一个指针,指向数组在内存中的开头位置。可以想象一下有一个指针的数组,最终你会得到一个内存块,里面包含的是连续的指针,每个指针都指向内存中的某个数组,所以得到的是指向数组的指针的集合,也就是数组的数组。
#include <iostream>
int main()
{
int* array = new int[50];
int** a2d = new int*[50]; // 这里存储的是一个指针对象的缓冲区
std::cin.get();
}
三维数组(了解即可):
int*** a3d = new int**[50];
for (int i = 0; i < 50; i++)
{
a3d[i] = new int*[50];
for (int j = 0; j < 50; j++)
a3d[i][j] = new int[50]; // 两次解引用
// int** ptr = a3d[i];
// ptr[j] = new int[50];
}
a3d[0][0][0] = 0;
还是回到二维数组:
int** a2d = new int*[50]; // 这里存储的是一个指针对象的缓冲区
for (int i = 0; i < 50; i++)
a2d[i] = new int[50];
a2d[0][0] = 0;
a2d[0][1] = 0;
a2d[0][2] = 0;
因为是堆分配的,所以需要delete[]
来释放内存。但是要注意的是,delete[] a2d
只是一个保存实际整型数组的指针的数组,如果删除了会造成存储实际数组的那50个数组的200字节内存空间泄漏,因为我们无法访问到它们了。所以需要:
2. 缓存不命中
按上面的方法处理数组的数组会造成memory fragmentation(内存碎片)问题,我们不是在一个连续的内存缓冲区,即在一行中保存这25个整数,实际上是创建了5个单独的缓冲区,每个缓冲区有5个整数,除非你采取某些自定义分配方式或者采用内存池分配,它们会被分配到内存中完全随机的位置。所以我们读取完一行要跳到下一行读取数组内容时会导致cache miss(缓存不命中),这意味着我们会浪费时间从RAM中获取数据。实际上用这种方式遍历这25个整数要比我们只分配一个一维数组要慢得多(一维数组内存分配都在一行),最重要的一点是当你在编程和优化时,你可以优化的最重要的事情之一就是优化你的内存访问。所以如果你能将要访问的内存存储在一起,那么你在定位数据时会有更多的cache hits(缓存命中)以及更少的cache miss ,你的程序会更快。你能想出一个更好的方法来存储25个整数吗?
你可以把它们存储在一个一维数组里: