在C语言中为三维数组分配空间

在C语言中为三维数组分配空间,c,arrays,pointers,dynamic-memory-allocation,C,Arrays,Pointers,Dynamic Memory Allocation,这个问题已经得到了回答,但对我来说,有些事情仍然悬而未决,讨论时间太长,任何人都无法回复评论,此外,我想问一下我的实现中出现了什么问题 不管怎样,问题的解决。我想为三维数组3,h,w分配空间。我在做什么: int ***a = (int***)malloc(3 * sizeof(int*)); for (int i = 0; i < 3; i++) { a[i] = (int **) malloc(height * sizeof(int*)); } 所以现在我认为每个a[I][0

这个问题已经得到了回答,但对我来说,有些事情仍然悬而未决,讨论时间太长,任何人都无法回复评论,此外,我想问一下我的实现中出现了什么问题

不管怎样,问题的解决。我想为三维数组
3,h,w
分配空间。我在做什么:

int ***a = (int***)malloc(3 * sizeof(int*));
for (int i = 0; i < 3; i++)
{
   a[i] = (int **) malloc(height * sizeof(int*)); 
}
所以现在我认为每个
a[I][0]
基本上是一个二维数组的空间,数组的大小、高度和宽度;此外,对于
j!=0
初始化为
a[i][0]
j行

然后,我通过以下方式初始化值:

for (int c = 0; c < 3; c++){
  for (int i = 0; i < height; i++){
    for (int j = 0; j < width; j++){
      a[c][i][j] = i+j+c;
for(int c=0;c<3;c++){
对于(int i=0;i
但是,这是不正确的。我想通过以下方式将此作为分配2D数组的扩展练习:

int *a[height]; 
a[0] = (int*)malloc(height * width * sizeof(int));
for (int i = 1; i < height; i++){
  a[i] = a[i-1] + widht;
}
int*a[高度];
a[0]=(int*)malloc(高度*宽度*尺寸(int));
对于(int i=1;i
这样,a是一个长度高度的指针数组,
a[0]
被分配给整个2D数组,随后的指针指向它们各自的行,我只需调用
a[I][j]=some number;

我想做的是将这个2D想法扩展到3D案例,但遗憾的是我失败了

int ***a = (int***)malloc(3 * sizeof(int*));
这没有分配任何有意义的内容。特别是,它没有分配3D数组,甚至没有分配3D数组的一部分。它为3个整数指针分配空间,这没有任何意义。
int***
也没有任何意义

而是分配一个三维阵列:

int (*a)[y][z] = malloc( sizeof(int[x][y][z]) );

for(int i=0; i<x; i++)
  for(int j=0; j<y; j++)
    for(int k=0; k<z; k++)
      a[i][j][k] = something;

free(a);

为了解决OP的更高目标,我怀疑指向2D数组的指针就足够了


但根据OP的要求

…要为三维阵列分配空间

代码通常如何创建3D阵列?
下面的代码使用C99中提供的可变长度数组执行此操作。
(VLA可选地支持C11)


示例代码

void VT_3_dimensional_array(int height, int width) {
  assert(height > 0 && width > 0);

  int (*a2)[3][height][width] = malloc(sizeof *a2);
  printf("%p %zu\n", (void*) a2, sizeof *a2);
  if (a2 == NULL) {
    perror("Out of memory");
    exit(EXIT_FAILURE);
  }
  for (int c = 0; c < 3; c++) {
    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++) {
        (*a2)[c][i][j] = i + j + c;
      }
    }
  }

  // use a;
  for (int c = 0; c < 3; c++) {
    for (int i = 0; i < height; i++) {
      putchar('(');
      for (int j = 0; j < width; j++) {
        printf(" %X", (*a2)[c][i][j]);
      }
      putchar(')');
    }
    puts("");
  }

  free(a2);
}

int main() {
  VT_3_dimensional_array(5, 7);
  return 0;
}

请注意,从技术上讲,OP的代码使用了错误的大小。通常
sizeof(int*)
sizeof(int**)
的大小相同,因此没有太大的危害。但这确实表明对分配的混淆

// wrong type  -----------------------v  should be int**
int ***a = (int***)malloc(3 * sizeof(int*));

让我们先想象一下您正在尝试做什么,然后我将显示代码以达到目的:

  int ***         int **                int *                  int 

  +---+           +---+                 +---+                  +---+
a |   | ---> a[0] |   | ------> a[0][0] |   | ----> a[0][0][0] |   |
  +---+           +---+                 +---+                  +---+
             a[1] |   | ----+   a[0][1] |   | -+    a[0][0][1] |   |
                  +---+     |           +---+  |               +---+
             a[2] |   |     |            ...   |                ...
                  +---+     |           +---+  |               +---+
                            | a[0][h-1] |   |  |  a[0][0][w-1] |   | 
                            |           +---+  |               +---+
                            |                  |
                            |           +---+  |               +---+
                            +-> a[1][0] |   |  +--> a[0][1][0] |   |
                                        +---+                  +---+
                                a[1][1] |   |       a[0][1][1] |   |
                                        +---+                  +---+
                                         ...                    ...
                                        +---+                  +---+
                              a[1][h-1] |   |     a[0][1][w-1] |   |
                                        +---+                  +---+
类型:

  • 每个
    a[i][j][k]
    都有类型
    int
  • 每个
    a[i][j]
    都指向
    int
    对象序列的第一个元素,因此它必须具有类型
    int*
  • 每个
    a[i]
    都指向
    int*
    对象序列的第一个元素,因此它必须具有类型
    int**
  • a
    指向
    int**
    对象序列的第一个元素,因此它必须具有类型
    int***
由于您正在执行逐段嵌套分配,因此需要检查每个
malloc
调用的结果,如果出现错误,您将希望在退出之前清理所有以前分配的内存,否则您将面临内存泄漏的风险。不幸的是,没有真正干净或优雅的方法来执行此操作-您要么在周围带一个标志然后做一系列额外的测试,或者加入几个
goto
s。我将展示两种不同的方法,这两种方法都不是很好

第一种方法-当我们分配每个
a[i]
时,我们也分配每个
a[i][j]
(一种“深度优先”方法)并初始化每个
a[i][j][k]
。如果分配
a[i][j]
失败,我们必须通过
a[i][j-1]
取消分配所有
a[i]
,然后对
a[0]
a[i-1]
中的每一个重复该过程:

/**
 * Depth-first approach: allocate each a[i][j] with each a[i]
 */
int ***alloc1( size_t pages, size_t height, size_t width )
{
  size_t i, j, k;

  int ***a = malloc( sizeof *a * pages ); // allocate space for N int **
                                          // objects, where N == pages

  if ( !a )
    return NULL;

  for ( i = 0; i < pages; i++ )
  {
    a[i] = malloc( sizeof *a[i] * height );  // for each a[i], allocate space for
    if ( !a[i] )                             // N int * objects, where N == height
      goto cleanup_1;

    for ( j = 0; j < height; j++ )
    {
      a[i][j] = malloc( sizeof *a[i][j] * width ); // for each a[i][j], allocate      
      if ( !a[i][j] )                              // space for N int objects,
        goto cleanup_2;                            // where N == w

      for ( k = 0; k < width; k++ )
        a[i][j][k] = initial_value( i, j, k );
    }
  }
  goto done;

/**
 * Free all of a[i][0] through a[i][j-1], then free a[i]
 */
cleanup_2:
  while ( j-- )
    free( a[i][j] );
  free( a[i] );

/**
 * Free all of a[0] through a[i-1], then free a
 */
cleanup_1:
  while ( i-- )
  {
    j = height;
    goto cleanup_2;
  }
  free( a );
  a = NULL;

done:
  return a;  // at this point, a is either a valid pointer or NULL.
}
没有
goto
s!但是在我看来,代码并不“流动”。分配代码和清理代码之间没有那么清晰的分离,清理部分之间也有一些重复性

请注意,对于这两种方法,内存都不是连续的-紧跟在
a[0][0][h-1]
之后的元素不会是
a[0][1][0]
。如果需要所有数组元素在内存中相邻,则需要使用其他元素显示的方法:

int (*a)[h][w] = malloc( sizeof *a * 3 );

需要注意的是,如果
h
w
较大,您可能没有足够的连续分配内存来满足请求。

int(*a)[height][width]=malloc(3*sizeof*a);
应该为您提供一个3d数组。这不会创建一个指向高度、宽度大小的2D数组的指针吗?是的,
a
是指向2D数组的指针,可以与
a[i][j][k]一起使用
。为什么你不能只进行1D分配,然后自己编制索引?更紧凑,而且我不相信这两个乘法比所有内存遍历都要昂贵。更不用说更有效的堆使用率了。@unwind这将是更好的处理方法,然而,我只想练习一下这个技巧内存管理的y部分,数组到指针的衰减等等。我知道它不会分配整个数组,我想做的是分配3个
int**
@VahagnTumanyan类型的指针。为什么?你说你想要一个3D数组。指针到指针在这种情况下没有意义。只是作为处理几个点的练习任何维度的指针类型。此外,对
malloc
使用更正确的语法(语义?),如将返回的
void*
转换为正确的指针类型,并具有
(元素数*大小(类型))<代码> >而不是简单地分配数组。@ VAHAGNTUMYANYAN确保您不实际使用C++编译器,在这种情况下,您将得到奇怪的错误,而2)您无意中使用了一个27年历史的GCC版本,通过添加编译器选项<代码> -STD= C99 < /代码>或<代码> -STD= C。
int (*a2)[3][height][width] = malloc(sizeof *a2);

// 3 nested for loop as above
    (*a2)[c][i][j] = i + j + c;
void VT_3_dimensional_array(int height, int width) {
  assert(height > 0 && width > 0);

  int (*a2)[3][height][width] = malloc(sizeof *a2);
  printf("%p %zu\n", (void*) a2, sizeof *a2);
  if (a2 == NULL) {
    perror("Out of memory");
    exit(EXIT_FAILURE);
  }
  for (int c = 0; c < 3; c++) {
    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++) {
        (*a2)[c][i][j] = i + j + c;
      }
    }
  }

  // use a;
  for (int c = 0; c < 3; c++) {
    for (int i = 0; i < height; i++) {
      putchar('(');
      for (int j = 0; j < width; j++) {
        printf(" %X", (*a2)[c][i][j]);
      }
      putchar(')');
    }
    puts("");
  }

  free(a2);
}

int main() {
  VT_3_dimensional_array(5, 7);
  return 0;
}
0x80071980 420
( 0 1 2 3 4 5 6)( 1 2 3 4 5 6 7)( 2 3 4 5 6 7 8)( 3 4 5 6 7 8 9)( 4 5 6 7 8 9 A)
( 1 2 3 4 5 6 7)( 2 3 4 5 6 7 8)( 3 4 5 6 7 8 9)( 4 5 6 7 8 9 A)( 5 6 7 8 9 A B)
( 2 3 4 5 6 7 8)( 3 4 5 6 7 8 9)( 4 5 6 7 8 9 A)( 5 6 7 8 9 A B)( 6 7 8 9 A B C)
// wrong type  -----------------------v  should be int**
int ***a = (int***)malloc(3 * sizeof(int*));
  int ***         int **                int *                  int 

  +---+           +---+                 +---+                  +---+
a |   | ---> a[0] |   | ------> a[0][0] |   | ----> a[0][0][0] |   |
  +---+           +---+                 +---+                  +---+
             a[1] |   | ----+   a[0][1] |   | -+    a[0][0][1] |   |
                  +---+     |           +---+  |               +---+
             a[2] |   |     |            ...   |                ...
                  +---+     |           +---+  |               +---+
                            | a[0][h-1] |   |  |  a[0][0][w-1] |   | 
                            |           +---+  |               +---+
                            |                  |
                            |           +---+  |               +---+
                            +-> a[1][0] |   |  +--> a[0][1][0] |   |
                                        +---+                  +---+
                                a[1][1] |   |       a[0][1][1] |   |
                                        +---+                  +---+
                                         ...                    ...
                                        +---+                  +---+
                              a[1][h-1] |   |     a[0][1][w-1] |   |
                                        +---+                  +---+
/**
 * Depth-first approach: allocate each a[i][j] with each a[i]
 */
int ***alloc1( size_t pages, size_t height, size_t width )
{
  size_t i, j, k;

  int ***a = malloc( sizeof *a * pages ); // allocate space for N int **
                                          // objects, where N == pages

  if ( !a )
    return NULL;

  for ( i = 0; i < pages; i++ )
  {
    a[i] = malloc( sizeof *a[i] * height );  // for each a[i], allocate space for
    if ( !a[i] )                             // N int * objects, where N == height
      goto cleanup_1;

    for ( j = 0; j < height; j++ )
    {
      a[i][j] = malloc( sizeof *a[i][j] * width ); // for each a[i][j], allocate      
      if ( !a[i][j] )                              // space for N int objects,
        goto cleanup_2;                            // where N == w

      for ( k = 0; k < width; k++ )
        a[i][j][k] = initial_value( i, j, k );
    }
  }
  goto done;

/**
 * Free all of a[i][0] through a[i][j-1], then free a[i]
 */
cleanup_2:
  while ( j-- )
    free( a[i][j] );
  free( a[i] );

/**
 * Free all of a[0] through a[i-1], then free a
 */
cleanup_1:
  while ( i-- )
  {
    j = height;
    goto cleanup_2;
  }
  free( a );
  a = NULL;

done:
  return a;  // at this point, a is either a valid pointer or NULL.
}
/**
 * Breadth-first approach; allocate all a[i], then all a[i][j], then initialize
 */
int ***alloc2( size_t pages, size_t height, size_t width )
{
  size_t i, j, k;

  /**
   * Allocate space for N int ** objects, where N == pages
   */
  int ***a = malloc( sizeof *a * pages );

  if ( !a )
    return NULL;                        // allocation failed for initial sequence, return NULL

  for ( i = 0; i < pages; i++ )  // For each a[i], allocate N objects of type
  {                              // int *, where N == height
    a[i] = malloc( sizeof *a[i] * height );
    if ( !a[i] )
      break;
  }

  if ( i < pages )
  {
    while ( i-- )                       // allocation of a[i] failed, free up a[0] through a[i-1]
      free( a[i] );
    free( a );                          // free a
    return NULL;
  }

  for ( i = 0; i < pages; i++ )    
  {
    for ( j = 0; j < height; j++ )
    {
      a[i][j] = malloc( sizeof *a[i][j] * width ); // for each a[i][j], allocate    
      if ( !a[i][j] )                             // space for N int objects, 
        break;                                    // where N == width
    }
  }

  if ( j < h )
  {
    do
    {
      while ( j-- )                     // allocation of a[i][j] failed, free up a[i][0] through a[i][j-1]
        free( a[i][j] );                // repeat for all of a[0] through a[i-1].
      free( a[i] );
      j = h;
    } while ( i-- );
    free( a );                          // free a
    return NULL;
  }

  /**
   * All allocations were successful, initialize array contents
   */    
  for ( i = 0; i < pages; i++ )
    for ( j = 0; j < height; j++ )
      for ( k = 0; k < width; k++ )
        a[i][j][k] = initial_value( i, j, k );

  return a;
}
int (*a)[h][w] = malloc( sizeof *a * 3 );