为二维数组动态分配内存涉及几个问题:
- 数组元素是否需要连续;
- 数组是否规则。
一个声明如下的二维数组所分配的内存是连续的:
int matrix[2][5] = {{1,2,3,4,5},{6,7,8,9,10}};
不过,当我们用malloc
这样的函数创建二维数组时,在内存分配上会有几种选择。由于我们可以将二维数组当做数组的数组,因而“内层”的数组没有理由一定要是连续的。如果对这种数组使用下标,数组的不连续对程序员是透明的。
注意 连续性还会影响复制内存等其他操作,内存不连续就可能需要多次复制。
分配可能不连续的内存
下面的代码演示了如何创建一个内存可能不连续的二维数组。首先分配“外层”数组,然后分别用malloc
语句为每一行分配。
int rows = 2;
int columns = 5;
int **matrix = (int **) malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
matrix[i] = (int *) malloc(columns * sizeof(int));
}
因为分别用了malloc
,所以内存不一定是连续的,如图4-15所示。
图4-15:不连续分配
实际的分配情况取决于堆管理器和堆的状态,也有可能是连续的。
分配连续内存
我们会展示为二维数组分配连续内存的两种方法。第一种首先分配“外层”数组,然后是各行所需的所有内存。第二种一次性分配所有内存。
下面的代码片段演示了第一种技术,第一个malloc
分配了一个整数指针的数组,一个元素用来存储一行的指针,这就是图4-16中在地址500处分配的内存块。第二个malloc
在地址600处为所有的元素分配内存。在for
循环中,我们将第二个malloc
所分配的内存的一部分赋值给第一个数组的每个元素。
int rows = 2;
int columns = 5;
int **matrix = (int **) malloc(rows * sizeof(int *));
matrix[0] = (int *) malloc(rows * columns * sizeof(int));
for (int i = 1; i < rows; i++)
matrix[i] = matrix[0] + i * columns;
图4-16:用两次malloc
调用分配连续内存
从技术上讲,第一个数组的内存可以和数组“体”的内存分开,为数组“体”分配的内存是连续的。
下面是第二种技术,数组所需的所有内存是一次性分配的:
int *matrix = (int *)malloc(rows * columns * sizeof(int));
分配的情况如图4-17所示。
图4-17:用一次malloc
调用分配连续内存
后面的代码用到这个数组时不能使用下标,必须手动计算索引,如下代码片段所示。每个元素被初始化为其索引的积:
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
*(matrix + (i*columns) + j) = i*j;
}
}
不能使用数组下标是因为我们丢失了允许编译器使用下标所需的“形态”信息。这个概念在传递多维数组讲过了。
实际项目中很少使用这种方法,但它确实说明了二维数组概念和内存的一维本质的关系。便捷的二维数组表示法让这种映射变得透明且更容易使用。
我们已经演示了为二维数组分配连续内存的两种方法,具体使用哪种要看应用程序的需要。不过第二种方法是为“整个”数组分配一块内存。
评论前必须登录!
注册