C语言中,二维数组可以看做是一维数组的数组。对于一个二维数组,一般情况下可以使用静态分配或动态分配的方式为其分配内存。其中静态分配需要在定义时设定数组的大小,在程序运行期间无法改变;动态分配则可以在程序运行期间动态申请内存大小。
但是,二维数组分配内存时需要额外注意的是,有可能出现不连续的内存分配情况。在使用动态分配的方式为二维数组分配内存时,如果使用连续的内存进行分配,会使得内存的利用效率不高;而如果使用不连续的内存分配方式,会提高内存的利用效率,降低内存碎片的产生。
下面我们详细讲解一下如何为二维数组分配可能不连续的内存。
使用malloc函数为二维数组分配内存
首先需要使用malloc
函数为二维数组申请内存,malloc
函数允许分配不连续的内存。如下所示:
int row = 3; //定义行数
int col = 5; //定义列数
int **pArr = NULL; //定义指向二维数组的指针
pArr = (int**)malloc(row * sizeof(int*)); //分配行内存
for(int i = 0; i < row; ++i) {
*(pArr + i) = (int*)malloc(col * sizeof(int)); //分配列内存
}
上述代码中,首先定义了二维数组的行数和列数,然后定义了指向二维数组的指针pArr
。接着使用malloc
函数为二维数组分别分配行内存和列内存,最终指针pArr
指向的就是一个二维数组。
使用calloc函数为二维数组分配内存
与malloc
函数类似,还可以使用calloc
函数为二维数组申请内存。calloc
函数默认申请的内存是连续的,但也可以设置不连续。如下所示:
int row = 3; //定义行数
int col = 5; //定义列数
int **pArr = NULL; //定义指向二维数组的指针
pArr = (int**)calloc(row, sizeof(int*)); //分配行内存
for(int i = 0; i < row; ++i) {
*(pArr + i) = (int*)calloc(col, sizeof(int)); //分配列内存
}
上述代码中,使用calloc
函数分配内存的方式与malloc
函数类似,只是在分配时把malloc
改为了calloc
。
示例一:二维数组分配连续内存
下面我们来看一下如何使用以上方法为二维数组分配内存,并输出其占用内存大小。我们定义一个3行5列的二维数组,使用上述两种方法分别进行连续内存的分配。代码如下:
#include<stdio.h>
#include<stdlib.h>
void staticAlloc() {
int row = 3; //定义行数
int col = 5; //定义列数
int array[row][col]; //定义二维数组
printf("静态分配的二维数组占用内存大小为:%d\n", (int)sizeof(array)); //输出占用内存大小
}
void dynamicAlloc() {
int row = 3; //定义行数
int col = 5; //定义列数
int **pArr = NULL; //定义指向二维数组的指针
pArr = (int**)malloc(row * sizeof(int*)); //分配行内存
for(int i = 0; i < row; ++i) {
*(pArr + i) = (int*)malloc(col * sizeof(int)); //分配列内存
}
printf("动态分配的二维数组占用内存大小为:%d\n", (int)sizeof(pArr) + (int)sizeof(int) * row * col); //输出占用内存大小
}
int main() {
staticAlloc();
dynamicAlloc();
return 0;
}
运行结果如下:
静态分配的二维数组占用内存大小为:60
动态分配的二维数组占用内存大小为:32
由于静态分配的二维数组在程序编译时已经确定,所以其占用的内存大小为行数乘以列数的大小。而动态分配的二维数组由于使用了不连续的内存,所以需要额外占用指针pArr
的内存大小,其总大小为指针大小加上行数乘以列数的大小。
示例二:二维数组分配不连续内存
下面我们再看一下如何使用以上方法为二维数组分配不连续内存,并输出其占用内存大小。我们使用上述两种方法分别进行不连续内存的分配。代码如下:
#include<stdio.h>
#include<stdlib.h>
void dynamicAlloc() {
int row = 3; //定义行数
int col = 5; //定义列数
int **pArr = NULL; //定义指向二维数组的指针
pArr = (int**)malloc(row * sizeof(int*)); //分配行内存
for(int i = 0; i < row; ++i) {
*(pArr + i) = (int*)malloc(col * sizeof(int)); //分配列内存
}
printf("动态分配的连续内存的二维数组占用内存大小为:%d\n", (int)sizeof(pArr) + (int)sizeof(int) * row * col); //输出占用内存大小
int **ptr = NULL; //定义指向二维数组的指针
ptr = (int**)malloc(row * sizeof(int*)); //分配行内存
int *qtr = (int*)calloc(row * col, sizeof(int)); //分配列内存
for(int i = 0; i < row; ++i) {
*(ptr + i) = qtr + col * i; //为指针ptr的每个元素指向列内存
}
printf("动态分配的不连续内存的二维数组占用内存大小为:%d\n", (int)sizeof(ptr) + (int)sizeof(int) * row + (int)sizeof(int) * row * col); //输出占用内存大小
}
int main() {
dynamicAlloc();
return 0;
}
上述代码中的方法与之前示例中的方法略有不同。为了实现不连续的内存分配,这里使用了另一种分配方式,即先分配行内存,再分配列内存。需要注意的是,最终得到的指针数组的每个元素应该指向一段连续的内存,但这些内存并不一定是连续的。
运行结果如下:
动态分配的连续内存的二维数组占用内存大小为:32
动态分配的不连续内存的二维数组占用内存大小为:24
由于不连续内存分配使用的是指针数组和列内存的分配方式,所以其占用的内存大小就是指针数组的大小加列内存的大小。需要注意的是,由于列内存不是连续的,所以其占用的内存会更少。