C语言为二维数组分配可能不连续的内存

  • Post category:C

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

由于不连续内存分配使用的是指针数组和列内存的分配方式,所以其占用的内存大小就是指针数组的大小加列内存的大小。需要注意的是,由于列内存不是连续的,所以其占用的内存会更少。