【问题标题】:C function for deallocating memory of 2D, 3D... arrays用于释放 2D、3D... 数组内存的 C 函数
【发布时间】:2016-08-10 22:37:50
【问题描述】:

我有一个问题,在我的设置中我有这样的变量:

bool** array_2d_bool;
char** array_2d_char;

...

所以,为了释放内存,我有以下几点:

void free_bool(bool** mat, int m)
{
    int i;
    for (i = 0; i < m; i++)
    {
        free(mat[i]);
    }
    free(mat);
}

但是,我必须为要释放的每种类型的 2D 或 3D 数组编写一个函数。有没有办法写出这样的函数?:

void deallocate_2d(void**, int m)

这样我就可以只使用一个函数来释放任何二维数组...

【问题讨论】:

  • 它会抛出编译器错误,例如“预期为 void**,已传递 char**”
  • 您没有 2D 或 3D 数组,并注意到可以作为一个数组使用。

标签: c pointers memory-management dynamic


【解决方案1】:

您没有 nD 数组。指针不是数组。它们也有不同的语义。

使用真正的 nD 数组可以直接解除分配:

#define INNER 10
#define OUTER 20

int (*arr)[INNER] = malloc(sizeof(*arr) * OUTER);

...

free(arr);

除了声明之外,这对于更多维度都是直截了当的。 freeing 甚至是一样的。不需要单独的释放函数。

【讨论】:

    【解决方案2】:

    在计算科学中,malloc() 一个一维“数组”(即m 由n 矩阵doubles,做一个double *a=malloc(m*n*sizeof(double)))是非常标准的,然后自己进行索引计算,即获取存储在a 中的i,j 的元素,使用a[i*n+j]。这有几个优点,包括它消除了执行多个/嵌套malloc()s 和free()s 的需要,对程序员的认知开销几乎没有增加,特别是因为您可以在一个很少的内联函数或宏,并且很容易扩展到更高的维度。

    更详细的解释可以在this answer找到。

    【讨论】:

    • 这种技术自 1999 年以来就已经过时了。现在有 VLA,更重要的是,有指向 VLA 的指针。不需要“错位”的二维数组。甚至在 C99 之前,您也可以使用具有固定维度的数组指针。
    • 如果使用 nD 数组,则不需要嵌套 malloc/free。您将苹果(数组/指向数组的指针)与橘子(指向指针的指针)进行比较。手动进行索引计算很笨拙且容易出错。
    • @Lundin 据我了解 1) VLA 在 C11 中是可选的,2) 大多数实现使用 VLA 的堆栈,这使得它们即使对于中等大小的矩阵也毫无用处。
    • @Olaf 我不同意手动进行索引计算是笨拙且容易出错的。如果您只想进行标准索引,则可以轻松地将其封装在一个内联函数中,该函数使用起来不会比原生索引更笨拙和容易出错。如果您想做或预计您将来可能想尝试非标准索引(例如 Morton 索引),至少是可能的。
    • @Emmet:使用函数来做语言已经提供的事情不是吗?请注意,您始终必须向该函数传递四个参数:数组、两个索引和至少内部维度。是的,这并不笨拙... Re VLA:在谈论它甚至没有提到的东西之前,请先阅读标准。 C 标准甚至没有为对象强制执行特定的内存方案,因此与 VLA 或任何其他类型的“堆栈”无关。是的,您可以很好地使用指向 VLA 的指针,从而使用具有自然索引的真正二维数组。
    【解决方案3】:
    bool** array_2d_bool;
    char** array_2d_char;
    

    这些不是二维数组,不能用于指向二维数组。充其量它们可以用来指向指针数组的第一个元素。

    您想要使用指针数组的唯一原因是当您想要一个查找表时,其中每个指向的类型都有不同的长度,例如字符串查找表或链式哈希表。这不是这里的情况,你只需要一个二维数组。

    使用指针到指针动态分配 2D 数组总是错误的,原因有很多:它不会创建实际的数组(所以你不能使用 memcpy() 和类似的上),它涉及复杂的分配/释放,可能导致泄漏,导致堆分段和更慢的分配,缓存性能差等等。

    而是分配一个二维数组:

    malloc( sizeof(bool[x][y] );
    

    然后用数组指针指向它。

    bool (*array_2d_bool)[x][y] = malloc( sizeof(bool[x][y] );
    

    为了便于使用,指向这个数组数组中的第一个数组比指向整个二维数组要方便得多。所以改成这样:

    bool (*array_2d_bool)[y] = malloc( sizeof(bool[x][y] );
    

    现在您可以将其用作array_2d_bool[i][j]。

    当你完成后,释放它:

    free(array_2d_bool);
    

    【讨论】:

    • 我已经习惯了这里给出的一些答案,“为二维数组分配内存”:stackoverflow.com/questions/17134650/…。这是否意味着,如果我想创建一个 mxn 矩阵,使用双指针然后为每个指针分配内存是一个坏主意?
    • @dpalma 那些答案不是很好,canonical duplicate 中有更好的答案。正如我在这个答案中所写的那样,您想要使用双指针(指向指针数组中的第一项的指针)的唯一原因是因为您需要各个项目彼此之间具有不同的长度。最明显的例子是指向 char(字符串)的指针数组。不过那不是二维数组。
    • 另一个问题...我想我不太明白,如果我想创建一个在运行时定义的大小的二维数组(m 和 n 仅用于测试目的),如果我这样做这个:pastebin.com/ECxF4F77我遇到了一个段错误......那么,那里有什么问题?
    猜你喜欢
    • 2015-03-06
    • 2015-03-04
    • 2016-10-25
    • 2013-01-27
    • 1970-01-01
    • 1970-01-01
    • 2015-09-05
    • 1970-01-01
    • 2012-11-06
    相关资源
    最近更新 更多