【问题标题】:How to allocate a 3 dimensional array in C? [duplicate]如何在 C 中分配一个 3 维数组? [复制]
【发布时间】:2014-07-21 21:03:18
【问题描述】:

在 C 中创建二维数组很容易:

char (*arr)[50] = malloc(sizeof(arr) * 10 * 50); // 10x50 matrix

如何在 C 中处理三维数组?看起来我不能这样做:

char (**arr)[50] = malloc(sizeof(arr) * 10 * 20 * 50); // 10x20x50 matrix?

【问题讨论】:

  • sizeof(char) * 10 * 50 将是一个 10x50 的字符矩阵,不是吗?
  • @RickyMutschlechner 会的。 :) 但它是一个二维矩阵。但我想知道如何做 3-dim...
  • @RudyVelthuis 和写 sizeof(char) 一样。 (编辑:我认为)
  • arr是一个指针,所以它的大小和sizeof(char)不一样。
  • "但它是一个二维矩阵。" -- 不,不是。

标签: c arrays malloc


【解决方案1】:

三维数组需要二维才能知道

char (*arr)[20][50] = malloc(sizeof(char) * 10 * 20 * 50)

注意:我已将 sizeof(arr) 更正为 sizeof(char),因为 sizeof(arr) 将返回指针的大小。

【讨论】:

  • sizeof(char) 总是多余的...
  • 在这种情况下,你做错了。 sizeof ***arr 有一定道理,但最好的情况下,文档会变得陈旧且没有错误。
  • @bodacydo:你真的应该在这里按照这个食谱做,它会做你想做的一切 - stackoverflow.com/a/2306802/2591612
  • @bodacydo:如果你认为这是一个很好的回应,那么请给回应的作者一个忙并点赞。
  • malloc( sizeof *arr * 10) 会更好。
【解决方案2】:

一种可能的方法是分配一个单维数组,例如

 int width=10; length=20; height=50;
 char* arr = malloc(width*length*height);
 if (!arr) { perror("malloc"); exit(EXIT_FAILURE); };

然后有一些方法可以访问它,例如宏

 #define Element(I,J,K) arr[width*length*(I)+length*(J)+(K)]

并使用Element(i,j,k)

您可以使用 flexible array member 之类的方式打包所有这些

 struct my3dstring_st {
   int width;
   int length;
   int height;
   char arr[];
 };

然后有一个。制作函数

  struct my3dstring_st *
  make_my3dstring (int width, int length, int height)
  { 
    if (width<=0 || length<=0 || height<=0) return NULL;
    struct my3dstring_st* s = 
       malloc(sizeof(struct my3dstring_st) 
              + width * length * height);
    if (!s) {perror("malloc"); exit(EXIT_FAILURE); };
    s->width = width;
    s->length = length;
    s->height = height;
    memset (s->arr, 0, width * length * height);
    return s;
  }

和一个内联访问函数(在头文件中):

  static inline int 
  access_m3dstring(struct my3dstring_st*s, int i, int j, int k) {
     if (!s || i<0 || j<0 || k<0 
         || i>=s->width || j>=s->height || k>=s->length) return EOF;
     return s->arr[i*->width*s->height + j*s->height + k];
   }

我作为练习留下来编写修改函数modify_m3dstring,你可能会有不安全但更快的变体,它们不做任何检查......

【讨论】:

  • 谢谢,这很酷!修改功能可以很简单Element[i,j,k] = x;:)
  • 如果你想修改一些作为参数传递的struct my3dstring_st*指针,则不需要。我的宏 Element 仅在 arrglobal 变量(或形式参数,但这很难看)时才有效。
  • static inline int access_m3dstring(struct my3dstring_st*s, int i, int j, int k, char val) { if (!s || i&lt;0 || j&lt;0 || k&lt;0 || i&gt;=s-&gt;width || j&gt;=s-&gt;height || k&gt;=s-&gt;length) return EOF; s-&gt;arr[i*-&gt;width*s-&gt;height + j*s-&gt;height + k] = val; }
  • 我的意思是edit_m3dstring! s-&gt;arr[i*-&gt;width*s-&gt;height + j*s-&gt;height + k] = val。是相关部分。还有char val在功能规范中。
  • calloc 可能比malloc + memset 更好。一些操作系统有一种更优化的方式来提供零初始化块。
【解决方案3】:

一般规则:

T *arr         = malloc( sizeof *arr * n ); // for an N-element array
T (*arr)[N]    = malloc( sizeof *arr * m ); // for an NxM-element array
T (*arr)[N][M] = malloc( sizeof *arr * k ); // for an NxMxK-element array

其中大写字母表示编译时已知的值,小写字母表示运行时已知的值。高维数组的模式应该很明显。

如果您使用支持可变长度数组的 C99 编译器或 C2011 编译器,则可以对所有维度使用运行时变量:

size_t n = some_value();
size_t m = some_other_value();
size_t k = yet_another_value();

T (*arr)[n][m] = malloc( sizeof *arr * k );

表达式*arr的类型是T [n][m],所以sizeof *arr给出的结果与sizeof (T) * n * m相同;结果更易于阅读且不易出错。

如果您的编译器不支持 VLA 并且您在编译时不知道您的尺寸,您将不得不分配为一维数组并手动计算偏移量:

T *arr = malloc( sizeof *arr * n * m * k );
...
arr[ 3*n*m + 2*m + 1] = x; // equivalient to arr[3][2][1] = x

或者,如果你可以忍受你的行在内存中不相邻,你可以零碎地分配数组:

T ***arr = malloc (sizeof *arr * n );
for (size_t i = 0; i < n; i++ )
{
  arr[i] = malloc( sizeof *arr[i] * m );
  for (size_t j = 0; j < m; j++ )
  {
    arr[i][j] = malloc( sizeof *arr[i][j] * k )
  }
}

理想情况下,您应该检查每个malloc 的结果以确保它成功。而且您必须按照分配它的相反顺序释放该数组:

【讨论】:

    【解决方案4】:
    char (*arr)[20][50] = malloc(sizeof(char) * 10 * 20 * 50);
    

    sizeof(char)保证为1,所以可以省略。

    char (*arr)[20][50] = malloc(10 * 20 * 50);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-09
      • 2015-06-23
      • 2017-09-28
      • 1970-01-01
      • 2018-03-12
      相关资源
      最近更新 更多