【问题标题】:How to properly allocate true 3D array in C如何在 C 中正确分配真正的 3D 数组
【发布时间】:2021-05-09 03:42:04
【问题描述】:

我目前正在努力寻找在 C89 中动态分配真正的 3D 数组的正确方法。这样做的目的是为 3D 笛卡尔网格创建存储。没有所谓的三星级节目,能做到吗?

【问题讨论】:

  • 什么(你认为)是“真正的 3D 阵列”?它与 int hoge[64][64][64]; 这样的简单数组有何不同?
  • tree-star 有什么问题?如果你想要 3D 数组,你需要“指向指针的指针”.. 其中每一个都将指向“指向指针的指针”,并且每个都指向“指针”。这有什么问题?
  • C89?你陷入什么残酷的境地?你需要帮助吗?如果需要救援,请闪烁三下。
  • int p[X][Y][Z] 和 int p[X * Y * Z] 之间只有语义上的区别,它们都是“3D”数组。
  • @DarkAtom 您可以执行类似int (*p)[10][10][10] = malloc(10*10*10*sizeof(int)); 的操作 - 并且p 将是一个指针,指向一个带有所有类型检查的完全连续的 3D 数组。

标签: c multidimensional-array dynamic-memory-allocation


【解决方案1】:

通过“真正的”3D 数组,我假设您的意思是所有元素都在一个连续的块中。在这种情况下,您最好的选择是这样的:

/**
 * Allocate an NxRxC array of some arbitrary type T
 */
T (*arr)[R][C] = malloc( sizeof *arr * N );

给你

     T (*)[R][C]        T 
     +---+             +---+      
arr: |   | ----------->|   | arr[0][0][0]
     +---+             +---+
                       |   | arr[0][0][1]
                       +---+
                        ...
                       +---+
                       |   | arr[0][0][C-1]
                       +---+
                       |   | arr[0][1][0]
                       +---+
                        ...
                       +---+ 
                       |   | arr[0][R-1][C-1]
                       +---+
                       |   | arr[1][0][0] 
                       +---+
                        ...

您只能将三重指针用于零碎的“锯齿状”数组分配(为简洁起见省略了错误检查):

T ***a = malloc( sizeof *a * N )
for ( size_t i = 0; i < N; i++ )
{
  a[i] = malloc( sizeof *a[i] * R );
  for ( size_t j = 0; j < C; j++ )
  {
    a[i][j] = malloc( sizeof *a[i][j] * C );
  }
}

这会给你这样的东西:

   T ***        T**             T*                  T
   +---+       +---+            +---+              +---+---+---+---+---+
a: |   |------>|   | a[0] ----->|   | a[0][0] ---->|   |   |   |   |   |...
   +---+       +---+            +---+              +---+---+---+---+---+
               |   | a[1] --+   |   | a[0][1] --+  
               +---+        |   +---+           |  +---+---+---+---+---+
                ...         |    ...            +->|   |   |   |   |   |...
                            |                      +---+---+---+---+---+
                            |
                            |   +---+              +---+---+---+---+---+
                            +-->|   | a[1][0] ---->|   |   |   |   |   |...
                                +---+              +---+---+---+---+---+
                                |   | a[1][1] --+
                                +---+           |  +---+---+---+---+---+
                                 ...            +->|   |   |   |   |   |...
                                                   +---+---+---+---+---+

当行的长度不必相同时,或者当您绝对不能将整个数组分配到单个连续块中时,您将使用第二种方法。

【讨论】:

    【解决方案2】:

    函数 malloc 不知道您要分配什么样的数组。它只是分配用户指定大小的内存范围。

    您需要正确声明指向已分配内存的指针,您可以使用类似的表达式

    a[i][j][k]
    

    访问已分配数组的元素,其中 i、j 和 k 是一些索引。

    您可以分配一个三维数组,例如以下方式

    enum { N1 = 2, N2 = 3, N3 = 4 };
    
    int ( *a )[N2][N3] = malloc( sizeof( int[N1][N2][N3] ) );
    

    或

    int ( *a )[N2][N3] = malloc( N1 * sizeof( int[N2][N3] ) );
    

    或

    int ( *a )[N2][N3] = malloc( N1 * sizeof( *a ) );
    

    或喜欢

    int ( *a )[N2][N3] = malloc( N1 * N2 * sizeof( int[N3] ) );
    

    或

    int ( *a )[N2][N3] = malloc( N1 * N2 * sizeof( **a ) );
    

    甚至喜欢

    int ( *a )[N2][N3] = malloc( N1 * N2 * N3 * sizeof( int ) );
    

    或

    int ( *a )[N2][N3] = malloc( N1 * N2 * N3 * sizeof( ***a ) );
    

    如果您的编译器支持可变长度数组,则 N1、N2 和 N3 不必是整数常量表达式。

    这是一个演示程序。

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void) 
    {
        enum { N1 = 2, N2 = 3, N3 = 4 };
        int ( *a )[N2][N3];
        
        a  = malloc( sizeof( int[N1][N2][N3] ) );
        
        free( a );
        
        a = malloc( N1 * sizeof( int[N2][N3] ) );
        
        free( a );
        
        a = malloc( N1 * sizeof( *a ) );
        
        free( a );
        
        a = malloc( N1 * N2 * sizeof( int[N3] ) );
        
        free( a );
        
        a = malloc( N1 * N2 * sizeof( **a ) );
        
        free( a );
        
        a = malloc( N1 * N2 * N3 * sizeof( int ) );
        
        free( a );
        
        a = malloc( N1 * N2 * N3 * sizeof( ***a ) );
        
        free( a );
        
        return 0;
    }
    

    如果您的编译器不支持可变长度数组并且您需要在运行时确定三维数组的大小,那么您可以分配一个一维数组并使用索引表达式模拟一个三维数组,或者您将需要分配数组的数组。

    例如

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void) 
    {
        enum { N1 = 2, N2 = 3, N3 = 4 };
    
        int ***a = malloc( N1 * sizeof( int ** ) );
        
        for ( size_t i = 0; i < N1; i++ )
        {
            a[i] = malloc( N2 * sizeof( int * ) );
            for ( size_t j = 0; j < N2; j++ )
            {
                a[i][j] = malloc( N3 * sizeof( int ) );
            }
        }
        
        //...
        
        for ( size_t i = 0; i < N1; i++ )
        {
            for ( size_t j = 0; j < N2; j++ )
            {
                free( a[i][j] );
            }
            free( a[i] );
        }
        
        free( a );
        
        return 0;
    }
    

    【讨论】:

    • 感谢您的建议,但遗憾的是,它们似乎不需要我的需求...我的目标是在确定数组尺寸后分配数组,因此 N1、N2、N3 不会保持不变表达式。 Im C89 在确定所需尺寸后,我也无法 dealere int (*a) [N2][N3]。
    • @miker 正如我在这种情况下的答案中所写,您只有两种选择,要么分配一个一维数组,要么使用索引表达式来模拟对三维数组的访问,或者分配一个维数组)指针)数组。
    【解决方案3】:

    有几个选项。有些可能适合也可能不适合您的需求。

    静态数组

    如果数组的大小是编译时常量,可以这样声明:

    int arr[3][4][5];
    

    变长数组

    同上,但数组大小不需要是编译时常量。不过,这仅适用于本地数组,并且仅适用于 C99,因此不适用于您。

    int arr[n][m][p];
    

    或者,如果您希望按照@Eugene Sh 的建议动态分配它:

    int (*arr)[m][p] = malloc(sizeof(int) * n * m * p);
    

    动态内存分配

    使用malloc:

    int*** arr = malloc(sizeof(int) * n * m * p);
    

    或者,如果你不想要三重指针:

    int* arr = malloc(sizeof(int) * n * m * p);
    

    但是这个数组需要被索引为arr[i*p + j*m + k],而不是通常的arr[i][j][k]。

    【讨论】:

      猜你喜欢
      • 2015-08-04
      • 1970-01-01
      • 2020-07-07
      • 2013-11-30
      • 1970-01-01
      • 2011-11-11
      • 2013-08-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多