【问题标题】:Assign Memory to 3D array using triple pointer使用三重指针将内存分配给 3D 数组
【发布时间】:2012-06-02 15:48:38
【问题描述】:

我必须使用三重指针为 3D 数组分配内存。

#include <stdio.h>
int main()
{
    int m=10,n=20,p=30;
    char ***z;
    z = (char***) malloc(sizeof(char**)*m*n*p);
    return 0;
}

这是正确的做法吗?(我认为我的做法不正确。)

【问题讨论】:

标签: c pointers memory-management multidimensional-array


【解决方案1】:

如果您不需要在单个连续块中分配内存(IME 是通常的情况),您可以执行以下操作:

char ***z;
z = malloc(sizeof *z * m); // allocate m elements of char **
if (z)
{
  int i;
  for (i = 0; i < m; i++)
  {
    z[i] = malloc(sizeof *z[i] * n); // for each z[i], 
    if (z[i])                        // allocate n elements char *
    {
      int j;
      for (j = 0; j < n;j++)
      {
        z[i][j] = malloc(sizeof *z[i][j] * p); // for each z[i][j], 
        if (z[i][j])                           // allocate p elements of char
        {
           // initialize each of z[i][j][k]
        }
      }
    }
  }
}

请注意,您需要以相反的顺序释放此内存:

for (i = 0; i < m; i++)
{
  for (j = 0; j < n; j++)
    free(z[i][j];
  free(z[i]);
}
free(z);

如果你真的需要将内存分配到一个连续的块中,你有几个选择。您可以分配一个块并手动计算偏移量:

char *z = malloc(sizeof *z * m * n * p); // note type of z!
...
z[i * m + j * n + k] = some_value();

当你完成后,你只需要做一个free:

free(z);

如果你有一个支持可变长度数组的 C99 编译器或 C11 编译器,你可以这样做:

int m=..., n=..., p=...;
char (*z)[n][p] = malloc(sizeof *z * m);

这将z 声明为指向charnxp 数组的指针,我们分配m 这样的元素。内存是连续分配的并且您可以使用普通的 3-d 数组索引语法 (z[i][j][k])。和上面的方法一样,只需要一个free调用:

free(z);

如果您没有支持 VLA 的 C99 编译器或 C11 编译器,则需要制作 np 编译时常量,例如

#define n 20
#define p 30

否则最后一个方法将不起作用。

编辑

m 在这种情况下不需要是编译时常量,只需 np

【讨论】:

  • C 中的const-qualified 对象不是一个编译时常量,C89 需要它作为数组维度。 C++ 在这方面是不同的。
【解决方案2】:

你想要sizeof(char) 而不是sizeof(char**),因为后者会给你一个指针的大小,在大多数现代系统上它将是 4 个字节,而不是你期望的 1 个字节。

【讨论】:

  • 你甚至不需要sizeof(char),因为根据定义,它等于1。
【解决方案3】:

无需在 C 中强制转换 malloc() 的返回值。

如果您希望直接存储 m * n * p 字符(并自己计算地址),那么您当然不应该按 char ** 的大小来扩展分配。

你的意思是:

int m = 10, n = 20, p = 30;
char *z = malloc(m * n * p * sizeof *z);

这将分配 10 * 20 * 30 = 6000 字节。这可以看作是形成一个高度为p 的立方体,沿垂直轴的每个“切片”为n * m 字节。

由于这是用于手动寻址,因此您不能使用例如z[k][j][i] 索引,而不是你必须使用z[k * n * m + j * m + i]

【讨论】:

    【解决方案4】:

    您将需要以下嵌套循环 -

    z = (char**)malloc(sizeof(char*) * m);
    for (int i = 0; i < m; ++i)
    {
        *(z + i) = (char*)malloc(sizeof(char*) * n);
        for (int j = 0; j < n; ++j)
        {
            *(*(z + i)) = (char)malloc(p);
        }
    }
    

    在句法上可能不准确,但应该是这样的。

    【讨论】:

    • 永远不要在 C 中转换 malloc 的结果。
    • 看在皮特的份上,使用数组索引符号而不是显式取消引用:z[i] 而不是 *(z + i)
    【解决方案5】:

    要完全分配 3D 动态数组,您需要执行以下操作:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int m=10,n=20,p=30;
        char ***z;
    
        z = malloc(m * sizeof(char **));
        assert(z != NULL);
        for (i = 0; i < m; ++i)
        {
            z[i] = malloc(n * sizeof(char *));
            assert(z[i] != NULL);
            for (j = 0; j < n; ++j)
            {
                z[i][j] = malloc(p);
                assert(z[i][j] != NULL);
            }
        }
        return 0;
    }
    

    释放数据留给读者作为练习。

    【讨论】:

    • 严格来说使用断言来处理运行时错误并不合适。
    • @Anders K: 是的 - 我只是想强调 malloc 可能会失败的事实,并且应该以某种方式处理这件事,而不会添加太多错误处理代码,以至于它会掩盖其余部分代码。我会看到我能找到更好的方法......
    • 非常好的解释使用指针为 3D 数组分配内存。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-23
    • 1970-01-01
    • 2020-09-22
    • 2011-01-16
    • 1970-01-01
    • 2021-04-13
    • 1970-01-01
    相关资源
    最近更新 更多