【问题标题】:How to allocate and declare a 3D of array of structs in C?如何在 C 中分配和声明 3D 结构数组?
【发布时间】:2015-04-23 14:28:48
【问题描述】:

如何在 C 中分配和声明 3D 结构数组? 您是先分配数组还是声明它? 我觉得你必须先分配它,这样你才能声明它,让它在堆上,但是你如何分配尚未制作的东西呢? 另外,您应该一次性分配还是逐个分配? 我是否也将结构正确放入数组中? 我对如何做到这一点的猜测是:

header.h

struct myStruct{
   int a;
   int b;
}; 
typedef struct myStruct myStruct_t;

ma​​in.c

#include "header.h"
#include <stdio.h>
#include <stdlib.h>
int main(void){

    int length=2;
    int height=3;
    int width =4;
    myStruct_t *elements;
    struct myStruct arr = (*myStruct_t) calloc(length*height*width, sizeof(myStruct);
    //zero based array
    arr[length-1][height-1][width-1];

    int x=0;
    while(x<length){
        int y=0;
        while(y<height){
            int z=0;
            while(z<depth){
                arr[x][y][z].a=rand();
                arr[x][y][z].b=rand();
                z++;
            }
            y++;
        }
        x++;
    }
    return 0;
}    

【问题讨论】:

标签: c arrays struct typedef allocation


【解决方案1】:

简单的方法是:

 myStruct_t (*arr2)[height][width] = calloc( length * sizeof *arr );

然后你的循环可以访问arr2[x][y][z].a = rand(); 等等。如果您不熟悉这种调用callocsee here 的方式。与 malloc 一样,在继续之前检查 arr2NULL

三指针方法并不是真正实用的解决方案。如果你的编译器不支持可变修改类型,那么数组应该被展平为一维。

【讨论】:

  • 正如@Forss 所指出的,不幸的是,可变长度数组(以及指向此类的指针)在 C11 中成为可选功能。
  • @jschultz410 这并不意味着它们不应该在可用的地方使用。好的代码可以在所有好的编译器上运行,如果它必须在 C89 或惰性供应商 C11 上运行,那么你可以使用一个丑陋的选项(我建议扁平化而不是三指针)
  • 是的,我完全同意。我只是觉得遗憾的是,C11 标准将以前的强制部分(C99 中的 VLA)变成了可选部分。 Visual Studio* 在 Windows 上被广泛使用,AFAIK 无法在其上编译此代码。
  • @jschultz410 毫无疑问来自 MS 的政治压力。与附件 K 相同。
【解决方案2】:

有几种不同的方法可以做到这一点,具体取决于您想要什么。首先,您可以像这样在堆栈上分配您的数组(在 C99 和一些编译器中):

myStruct_t arr[length][height][depth];

如果您希望它在堆上分配,那么您可以进行适当大小的单次分配。然后,您可以自己进行索引计算或让指针为您完成工作(在 C99 和一些编译器中):

void *buf = malloc(length * height * width * sizeof(myStruct_t));
myStruct_t *arr = buf;
myStruct_t (*arr2)[height][width] = buf;

/* TODO: check return of malloc */
...

arr[x * height * width + y * width + z].a = rand();  /* indexing the C89 way */
arr2[x][y][z].b = rand();                            /* indexing the C99 way */

或者您可以手动分配多个维度。

#include <stddef.h>
#include <stdlib.h>

typedef struct myStruct
{
  int a, b;

} myStruct_t;

int main()
{
  myStruct_t ***arr;
  int length = 5000, height = 1000, depth = 20;
  int x, y, z;
  int ret = 1;

  if (NULL == (arr = malloc(length * sizeof(myStruct_t**))))
    goto FAIL;

  for (x = 0; x < length; ++x)
  {
    if (NULL == (arr[x] = malloc(height * sizeof(myStruct_t*))))
      goto FAIL_X;

    for (y = 0; y < height; ++y)
    {
      if (NULL == (arr[x][y] = malloc(depth * sizeof(myStruct_t))))
        goto FAIL_Y;

      for (z = 0; z < depth; ++z)
      {
        arr[x][y][z].a = rand();
        arr[x][y][z].b = rand();
      }
    }
  }

  /* TODO: rest of program logic */

  /* program successfully completed */

  ret = 0;

  /* reclaim arr */

FAIL_CLEANUP: /* label used by TODO code that fails */

  for (x = length - 1; x >= 0; --x)
  {
    for (y = height - 1; y >= 0; --y)
    {
      free(arr[x][y]);
    FAIL_Y:
      ;
    }

    free(arr[x]);
  FAIL_X:
    ;
  }

  free(arr);

FAIL:    
  return ret;
}

最后一个版本为它包含的所有显式指针使用了更多的内存,它的内存局部性更差,并且正确分配和回收要复杂得多。但是,它确实允许沿您的尺寸使用不同的尺寸。例如,如果您需要,数组 arr[0][4] 的大小可以与 arr[0][7] 不同。

如果您想在堆上分配它,那么您可能需要具有单个分配和多维指针(如果可用)的第二个版本,或者使用适当的数学手动进行索引。

【讨论】:

  • 为什么选择 myStruct**?为什么是两个 * 而不是 3?如果我想用 arr 的大小进行分配,该行是否会读取 arr = calloc(length, sizeof(struct ***arr)); ?
  • arr 被声明为 struct myStruct ***。它确实使用了 3 个 *。当你调用 calloc/malloc 时,返回值比你分配的类型多了一个间接性。因此,例如,顶级 calloc 返回一个 struct myStruct ***,因为我们分配了一个 struct myStruct ** 的数组。当您在 arr 的表达式上使用 sizeof 时,您不会重新添加结构。您只需说 sizeof(***arr),这相当于 sizeof(struct myStruct)。
  • @jschultz410 你认为malloc() 总是神奇地工作,而且永远不会失败?你的代码有潜在的未定义行为,编写安全的代码,并教导它。如果 OP 更喜欢您的代码,那么有一天您将使用他的一个应用程序,然后它会突然崩溃之类的。
  • @iharob 是的,你明白了:我认为 malloc 总是能神奇地工作。我的意思是展示如何进行多维分配,而不会因错误处理而混乱。当然,您总是需要检查和处理实际程序中的错误。 PS - 像这样将错误处理嵌入到主行代码中是很丑陋的。
  • 这当然是一团糟,但我认为否则 OP 会感到困惑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-23
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
  • 2018-05-13
  • 1970-01-01
  • 2016-02-19
相关资源
最近更新 更多