首页 > 解决方案 > 这种连续的 C 内存分配方法到底在做什么?

问题描述

我在寻找一种在内存中连续分配大型多维数组的有效方法时遇到了这个问题。公认的答案表明,对于大小为sz[0]x sz[1]x的 3D 数组,sz[2]应该使用这种方法,目前这种方法正在融化我虚弱的大脑:

int (*a)[sz[1]][sz[2]] = calloc(sz[0], sizeof(*a));
...
free(a)

该语句的左侧看起来像int *在堆栈上分配的二维数组。右侧是在堆上calloc()分配的单个(?!)调用。int *因为sizeof(*a)==sizeof(int *)(对吗?)这看起来分配太少而没有任何意义,因为它似乎分配了sz[0]xint *个字节,但它可以索引数组的完整预期大小。

有人可以帮我理解这个定义是如何产生预期结果的吗?C 编译器是否为左侧定义的表中的每个条目重复调用 calloc?如果是这样,一个电话如何free()足以摆脱它?生成的数组是完全驻留在堆上,还是在堆栈上混合了指向在堆上分配的内存的引用表?

标签: cmultidimensional-arraydynamic-memory-allocation

解决方案


这是一些具有相似原理的代码,起初可能更容易理解:

typedef int THING[5][6];    // THING means a contiguous array of 5x6 ints

THING arr[4];               // arr is a contiguous array of 4 THINGs
THING *first = &arr[0];     // The expression *first would yield the first thing.

希望您认识到这里的最后两行是对任何数组进行非动态分配的通用语法,并且指的是数组的第一个元素。无论 THING 本身是否是一个数组,这都是一样的。

现在,&arr[0]指向一个内存位置,它是大小为 4x5x6 的连续整数块的开始。如果您使用动态分配使该块看起来像:

THING *first = malloc( sizeof(int[4][5][6]) );

如果我们在最后一行扩展 typedef,它看起来像:

int (*first)[5][6] = malloc( sizeof(int[4][5][6]) );

您问题中的代码与最后一行相同,除了:

  • 它使用变量而不是硬编码的整数(自 C99 起允许使用)。
  • 它使用calloc而不是malloc.
  • 它使用更健壮的语法来计算要分配的大小,请参阅此处进行解释。

推荐阅读