2D和3D数组的动态分配/释放

12

我知道如何动态分配/释放二维数组的算法,但对于三维数组我不是很确定。
利用这些知识和一些对称性, 我想出了以下代码。
(编码时我在3D中很难形象化思考)。

请评论我的代码是否正确,并提出更好的替代方案(在效率或直观上),如果有的话。
此外,我认为这两个2D和3D数组可以像静态数组一样正常访问,例如 arr2D [2] [3] 和
arr3D [2] [3] [2]。 对吗?

2D代码:

//allocate a 2D array
int** allocate2D(int rows,int cols)
{
    int **arr2D;
    int i;

    arr2D = (int**)malloc(rows*sizeof(int*));
    for(i=0;i<rows;i++)
    {
        arr2D[i] = (int*)malloc(cols*sizeof(int));
    }
}

//deallocate a 2D array
void deallocate2D(int** arr2D,int rows)
{
    int i;

    for(i=0;i<rows;i++)
    {
        free(arr2D[i]);
    }

    free(arr2D);
}  

3D代码

//allocate a 3D array
int*** allocate3D(int l,int m,int n)
{
int ***arr3D;
int i,j,k;

arr3D = (int***)malloc(l * sizeof(int **));

for(i=0;i<l;i++)
{
    arr3D[i] = (int**)malloc(m * sizeof(int*));
    for(j=0;j<m;j++)
    {
        arr3D[i][j] = (int*)malloc(n*sizeof(int));
    }
}

return arr3D;
}

//deallocate a 3D array
void deallocate3D(int arr3D,int l,int m)
{
    int i,j;

    for(i=0;i<l;i++)
    {
        for(int j=0;j<m;j++)
        {
            free(arr3D[i][j]);
        }
        free(arr3D[i]);
    }
    free(arr3D);
}
4个回答

11

您还可以分配一个数组并计算单个索引。这样做需要更少的分配器调用,会导致更少的碎片和更好的缓存使用。

typedef struct {
  int a;
  int b;
  int* data;
} Int2d;

Int2d arr2d = { 2, 3 };
arr2d.data = malloc(arr2d.a * arr2d.b * sizeof *arr2d.data);

现在 arr2d[r][c] 变成了 arr2d.data[r * arr2d.b + c]。只需要一个 free() 即可完成释放内存。额外奖励是你一定能保持动态数组的大小。
推广到三维:
typedef struct {
  int a;
  int b;
  int c;
  int* data;
} Int3d;

Int3d arr3d = { 2, 3, 4 };
arr3d.data = malloc(arr3d.a * arr3d.b * arr3d.c * sizeof *arr3d.data);

//arr3d[r][c][d]
// becomes:
arr3d.data[r * (arr3d.b * arr3d.c) + c * arr3d.c + d];

你应该将这些索引操作(以及相关的(de-)allocations)封装在一个单独的函数或宏中。
(r、c 和 d 的名称可能可以更好地命名 - 我想使用 行、列和深度。虽然 a、b 和 c 是相应维度的限制,但您可能更喜欢在那里使用 n1、n2、n3 或甚至使用数组。)

你也可以在一个足够大的单块中分配n维数组,以包含指针和数据。这样,你就可以使用int ***** array = allocate (sizeof(int), 10, 10, 10, 10, 10, 0);来分配一个5D int数组,并通过array [a][b][c][d][e]进行索引,而无需计算索引。当我需要用堆栈数组替换大型堆栈数组以使代码适用于具有有限堆栈大小的手机时,我使用了这种方法,而不需要对索引数组的代码进行严重调整。请参见此处:https://sourceforge.net/p/gnugos60/code/HEAD/tree/trunk/GNUGoS60/common/src/ndMalloc.cpp - idij
做乘法的唯一问题似乎是潜在的溢出问题。就像BSD Unix中有一个reallocarray函数来替换realloc函数一样。 - codepoet

4

arr3d 应该是一个三级指针而不仅仅是一个整数。否则看起来没问题:

void deallocate3D(int*** arr3D,int l,int m)
{
    int i,j;

    for(i=0;i<l;i++)
    {
        for(int j=0;j<m;j++)
        {
                free(arr3D[i][j]);
        }
        free(arr3D[i]);
    }
    free(arr3D);
}

arr3D是一个指向指针的指针的指针,所以arr3D[i]是一个指向指针的指针,而arr3D[i][j]只是一个指针。在释放arr3D本身之前,先循环释放最低维度是正确的。

此外,更符合惯用法的是隐式地给malloc分配指向类型的大小。例如:

  arr3D[i] = (int**)malloc(m * sizeof(int*));

让它变得更好:

  arr3D[i] = (int**)malloc(m * sizeof(*arr3D[i]));

是的,这样动态分配的多维数组可以像静态分配的多维数组一样访问。


1
您可以看到以下代码:
#include <stdio.h>
#include <stdlib.h>

void main()
{
    //  Array 3 Dimensions
    int x = 4, y = 5, z = 6;

    //  Array Iterators
    int i, j, k;

    //  Allocate 3D Array
    int *allElements = malloc(x * y * z * sizeof(int));
    int ***array3D = malloc(x * sizeof(int **));

    for(i = 0; i < x; i++)
    {
        array3D[i] = malloc(y * sizeof(int *));

        for(j = 0; j < y; j++)
        {
            array3D[i][j] = allElements + (i * y * z) + (j * z);
        }
    }

    //  Access array elements
    for(i = 0; i < x; i++)
    {
        printf("%d\n", i);

        for(j = 0; j < y; j++)
        {
            printf("\n");

            for(k = 0; k < z; k++)
            {
                array3D[i][j][k] = (i * y * z) + (j * z) + k;
                printf("\t%d", array3D[i][j][k]);
            }
        }

        printf("\n\n");
    }

    //  Deallocate 3D array
    free(allElements);
    for(i = 0; i < x; i++)
    {
        free(array3D[i]);
    }
    free (array3D);
}

更多细节请查看此链接3D数组


0
这是问题中的一个版本,但只使用了一个malloc,受其他答案的启发。它允许直观地使用方括号并进行简单的清理。我希望它不会做出任何编译器实现特定的假设。
int main(int argc, char *argv[])
{
  int **array, i, j;
  array = allocate2d(3, 4);
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      array[i][j] = j + i + 1;
    }
  }
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      printf("array[%d][%d] = %d\n", i, j, array[i][j]);
    }
  }
  free(array);
  return EXIT_SUCCESS;
}

int **allocate2d(int x, int y)
{
  int i;
  int **array = malloc(sizeof(int *) * x + sizeof(int) * x * y);
  for (i = 0; i < x; i++)
  {
    array[i] = ((int *)(array + x)) + y * i;
  }
  return array;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接