C语言 多维数组的内存分配问题

C语言中,为多维数组分配内存并进行操作是一个常见的问题。使用动态内存分配来创建多维数组可以让数组的大小在运行时确定,而不是在编译时固定。使用连续内存块的方式是分配多维数组内存的最佳选择,具有较高的访问效率。每一维的内存都要正确分配,并且在程序结束时要释放内存以避免泄漏。对于简单的二维数组,可以使用单指针模拟二维数组来简化代码。

1、分配连续内存块(推荐)

常见的分配方式,分配一个大的内存块,然后按行或列进行索引。相比其他方法,它的内存布局是连续的,因此访问速度快,也更易于释放内存。

#include <stdio.h>
#include <stdlib.h>

int main() {
    int rows = 3, cols = 4;

    // 分配一个连续的内存块
    int *data = (int *)malloc(rows * cols * sizeof(int));

    if (data == NULL) {
        perror("Memory allocation failed");
        return 1;
    }

    // 创建指针数组,每个指针指向二维数组的一行
    int **array = (int **)malloc(rows * sizeof(int *));
    for (int i = 0; i < rows; i++) {
        array[i] = data + i * cols;
    }

    // 使用二维数组
    array[1][2] = 42;
    printf("array[1][2] = %d\n", array[1][2]);

    // 释放内存
    free(array);
    free(data);

    return 0;
}

2、分配不连续的内存块(每行独立分配)

为数组的每一行独立分配内存,虽然操作简单,但每一行在内存中的位置可能不是连续的。

#include <stdio.h>
#include <stdlib.h>
int main() {
    int rows = 3, cols = 4;
    // 分配指针数组
    int **array = (int **)malloc(rows * sizeof(int *));
    for (int i = 0; i < rows; i++) {
        array[i] = (int *)malloc(cols * sizeof(int));
    }
    // 使用二维数组
    array[1][2] = 42;
    printf("array[1][2] = %d\n", array[1][2]);
    // 释放内存
    for (int i = 0; i < rows; i++) {
        free(array[i]);
    }
    free(array);
    return 0;
}

3、单指针模拟二维数组

C语言中,二维数组在内存中是按行顺序存储的。可以利用这个特性,使用单指针来模拟二维数组。其基本思想是将二维数组看作是一个一维数组,通过计算偏移量来访问元素,使用单个指针,模拟二维数组的行为。

#include <stdio.h>
#include <stdlib.h>
int main() {
    int rows = 3, cols = 4;
    // 分配一块连续的内存
    int *array = (int *)malloc(rows * cols * sizeof(int));
    if (array == NULL) {
        perror("Memory allocation failed");
        return 1;
    }
    // 使用一维数组模拟二维数组
    array[1 * cols + 2] = 42;
    printf("array[1][2] = %d\n", array[1 * cols + 2]);
    // 释放内存
    free(array);
    return 0;
}

4、多维数组的内存分配错误示例

一个常见的错误示例,程序员误以为只分配一个指针数组就足够了:

#include <stdio.h>
#include <stdlib.h>
int main() {
    int rows = 3, cols = 4;
    // 错误:仅分配了指针数组,没有分配行内存
    int **array = (int **)malloc(rows * sizeof(int *));
    // 未正确分配内存会导致段错误(Segmentation Fault)
    array[1][2] = 42;  // 错误!
    // 释放内存(这也会导致未定义行为)
    free(array);
    return 0;
}

5、使用示例

使用连续内存块,因为它具有更高的访问速度,并且释放内存时不容易出错。确保每一维都分配了正确的内存,避免段错误或未定义行为。无论使用哪种方法,都需要确保使用 free() 释放所有分配的内存,以避免内存泄漏。

#include <stdio.h>
#include <stdlib.h>
int main() {
    int rows = 3, cols = 4;
    // 分配连续的内存块
    int *data = (int *)malloc(rows * cols * sizeof(int));
    int **array = (int **)malloc(rows * sizeof(int *));
    for (int i = 0; i < rows; i++) {
        array[i] = data + i * cols;
    }
    // 使用数组
    array[2][3] = 99;
    printf("array[2][3] = %d\n", array[2][3]);
    // 释放内存
    free(array);
    free(data);
    return 0;
}

推荐阅读
cjavapy编程之路首页