【问题标题】:dynamic allocation/deallocation of 2D & 3D arrays2D 和 3D 数组的动态分配/解除分配
【发布时间】:2010-12-21 21:57:39
【问题描述】:

我知道动态分配/取消分配 2D 数组的算法,但我不太确定 3D 数组是否相同。
利用这些知识和一点对称性,我想出了以下代码。
(在编码过程中,我很难在 3D 中进行可视化)。

如果有的话,请评论正确性并提出任何更好的替代方案(效率方面或直观)。
另外,我认为这些 2D 和 3D 数组都可以像 arr2D[2][3] 和
等静态数组一样正常访问 arr3D[2][3][2]。正确的?

二维码

//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);
}

【问题讨论】:

    标签: c memory dynamic memory-management dynamic-memory-allocation


    【解决方案1】:

    arr3d 应该是一个三重指针,而不仅仅是一个 int。否则看起来没问题:

    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 指定类型的sizeof 更为惯用。而不是:

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

    制作:

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

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

    【讨论】:

      【解决方案2】:

      您还可以分配一个数组并计算单个索引。这需要更少的分配器调用,从而减少碎片并更好地使用缓存。

      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() 即可。作为奖励,您一定要随身携带动态数组大小。

      外推到 3d:

      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];
      

      您应该将这些索引操作(以及与此相关的(取消)分配)封装在单独的函数或宏中。

      (r、c 和 d 的名称可能更好——我要的是行、列和深度。虽然 a、b 和 c 是它们对应维度的限制,但您可能更喜欢 n1 之类的名称, n2,n3 那里,甚至为它们使用一个数组。)

      【讨论】:

      • 您还可以在一个足够大的块中分配一个 n 维数组,以包含指针和数据。这样你就可以去 int ***** array = allocate (sizeof(int), 10, 10, 10, 10, 10, 0);分配一个 5D int 数组,并通过数组 [a][b][c][d][e] 对其进行索引,而无需计算索引。当我需要用堆数组替换大型堆栈数组来编码以在堆栈大小有限的手机上工作时,我使用了它,而无需对索引数组的代码进行认真的调整。见这里:sourceforge.net/p/gnugos60/code/HEAD/tree/trunk/GNUGoS60/common/…
      • 做乘法的唯一问题似乎是溢出的可能性。就像 BSD unix 中有一个 reallocarray 来替代 realloc 函数一样。
      【解决方案3】:

      你可以看到下面的代码:

      #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 array

      【讨论】:

        【解决方案4】:

        这是问题中想法的一个版本,但仅使用一个 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;
        }
        

        【讨论】:

          猜你喜欢
          • 2012-05-01
          • 2012-11-23
          • 2017-02-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多