【问题标题】:Heap allocate a 2D array (not array of pointers)堆分配一个二维数组(不是指针数组)
【发布时间】:2012-04-12 01:47:31
【问题描述】:

我正在编写 C 代码,我想堆分配 512*256 字节。为了我自己的方便,我希望能够使用语法 array[a][b]; 访问元素。没有算术来找到正确的索引。

我在网上看到的每个教程都告诉我创建一个指针数组,这些指针指向我想要在数组中包含的行的数组。这意味着每个子数组都需要单独进行 malloc 和 free 。我对只需要一次调用 malloc 和一次调用 free 的解决方案感兴趣。(因此所有元素都是连续的)我认为这是可能的,因为我不会构造锯齿状数组。

如果有人能分享声明这样一个数组的语法,我将不胜感激。

【问题讨论】:

  • C++ 是一种选择吗?您可以创建一个重载索引运算符的简单 C++ 对象。
  • @RichardJ.RossIII:这真的是对“我如何在 C 中做到这一点”这个问题的有效回答吗? (意识到您确实将其作为评论留下)。任何一天我都会用 C 代替 C++,谢谢。
  • @EdS。虽然您可能更喜欢 C,但 C++ 在很多情况下会更好,这就是其中之一。我把它作为评论留下只是为了确定它是否是一个选项。
  • @RichardJ.RossIII:C++ 更适合分配二维数组?嗯?我不这么认为,这在 C 中很容易实现,不需要 C++ 运算符重载。
  • 看我的回答;与其他人不同,它实际上可以满足您的要求。

标签: c multidimensional-array malloc


【解决方案1】:

好吧,如果要分配类型的数组,请将其分配给该类型的指针。

由于 2D 数组是数组的数组(在您的情况下,是 512 个 256 个字符的数组),您应该将它分配给一个指向 256 个字符的数组的指针:

char (*arr)[256]=malloc(512*256);
//Now, you can, for example:
arr[500][200]=75;

*arr 周围的括号是使其成为指向数组的指针,而不是指针数组)

【讨论】:

  • +1,不知何故我错过了你在我写答案时发布的这个。 :-)
  • 这正是我想要的。谢谢。
  • 请注意,从 C99 开始,不再需要在编译时知道尺寸。您可以让n,m 从标准输入中读取并声明char arr[n][m],或者在本例中为char (*arr)[n]
【解决方案2】:

如果你像这样分配数组,它需要两次调用free,但它允许array[a][b] 样式语法并且是连续的。

char **array = malloc(512 * sizeof(char *));
array[0] = malloc(512*256);
for (int i = 1; i < 512; i++)
    array[i] = array[0] + (256 * i);

更多信息请参见array2http://c-faq.com/aryptr/dynmuldimary.html

【讨论】:

  • 您可以通过将数据块紧跟在涂料向量之后来组合这两种分配。需要一定数量的繁琐类型转换,但并不难。但是,您的代码显示有一个严重的错误:您为 512 chars 分配了空间,然后您将其视为足够的空间用于 512 char *s。这几乎可以保证结束分配并崩溃。
  • 这不是一个二维数组,而是一个指针数组。它有一些优点(您可以置换 O(1) 中的行而不是 O(cols))和其他缺点(每次访问都更昂贵,因为它经过了额外的间接级别;它需要更多的内存;等等)。无论如何,如果您采用这种方法,请考虑 Zack 的建议,即仅使用单个 malloc。这简化了您的错误处理(无需清除部分故障情况)并确保内存局部性。
【解决方案3】:

这很容易假设您不需要与古老的 C89 标准兼容(在当前的 C 编译器中,只有 MSVC 和一些嵌入式目标编译器是向后的)。以下是你的做法:

int (*array)[cols] = malloc(rows * sizeof *array);

那么array[a][b][0,rows) 中的任何a[0,cols) 中的b 都有效。

在 C 标准的语言中,array 具有可变修改类型。如果要将指针传递给其他函数,则需要在函数参数列表中重复此类型,并确保至少将列数传递给函数(因为它需要作为可变修改的一部分类型)。

编辑:我错过了 OP 只关心固定尺寸 512x256 的事实。在这种情况下,C89 就足够了,您只需要:

int (*array)[256] = malloc(512 * sizeof *array);

如果您需要在函数之间传递指针(也可以作为函数返回类型,但对于这种用途,您可能需要 typedef 它... :-)

【讨论】:

  • 一般情况下你是对的,但 OP 只想要 512*256 数组。
  • 其实这个答案很好。虽然我现在只需要 512*256,但我很容易看到这个需求在未来会发生变化。
  • 我喜欢一般的案例方法,但无法理解一件事。它是否仍然需要遍历外部数组以释放所有内部指针?还是只需要调用一次 free()?
  • @sacheie:每个malloc 只能调用一次free;这总是正确的。 array 不是指针数组,而是数组数组。每个array[i]衰减指向其第一个元素的指针,但array[i]一个数组。
【解决方案4】:

由于您提前知道数组的大小,您可以创建一个包含 521x256 数组的struct 类型,然后动态分配struct

【讨论】:

    【解决方案5】:

    可以动态分配与

    相同类型的多维数组
    static char x[512][256];
    

    给你,但由于类型衰减,这有点棘手。我只知道如何使用typedef

    typedef char row[512];
    row *x = malloc(sizeof(row) * 256);
    

    这只允许您在运行时确定第二维的大小。如果两个维度在运行时都可以变化,则需要一个涂料向量。

    【讨论】:

    • 也错过了这个。请注意,除非您仅限于 C89,否则这两个维度都可能有所不同;您只需要使用可变修改的指针类型。
    【解决方案6】:

    如果你知道数组的大小,你可以typedef它,并做一个指向它的指针。这是一个简短的 sn-p 演示此用法:

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef int array2d[20][20];
    
    int main() {
        int i,j;
        array2d *a = malloc(sizeof(array2d));
        for(i=0;i!=20;i++)
            for(j=0;j!=20;j++)
                (*a)[i][j] = i + j;
    
        for(i=0;i!=20;i++)
            for(j=0;j!=20;j++)
                printf("%d ",(*a)[i][j]);
        free(a);
        return 0;
    }
    

    【讨论】:

    • 有趣的解决方案,你有什么办法可以弄清楚如何使用动态数组来做到这一点?
    • @RichardJ.RossIII 不幸的是,这不适用于动态大小的数组,因为 typedef 需要两个维度的编译时常量。您可以做的最好的事情是使一个维度固定而另一个动态,但这不会使其完全动态。
    • typedef 是不必要的,实际上将两个维度都放在 typedef 中是有害的,因为你被困在所有地方都使用(*a) 而不仅仅是简单的a。如果只放列数,效果会好很多。当然,使用 C99,您可以对类型进行可变修改;我相信这在 typedef 中甚至是有效的,只要 typedef 具有块范围而不是文件范围。
    【解决方案7】:

    所有很好的答案。对于像我这样喜欢在旧机器上使用 Turbo C 等旧编译器进行“复古”编码 16 位的老怪人,我只有一件事要补充。可变长度数组很棒,但不是必需的。

        char (*array)[81];
        int lineCount;
    
        /* Go get your lineCount.*/
        lineCount = GetFileLines("text.fil");
    
        array = malloc(lineCount * 81);
    

    这就是我们在过去制作“VLA”的方式。它的工作原理与

        char (*array)[81] = malloc(lineCount * 81);  /* error pre C99 */
    

    没有 VLA 的奢华。

    只是我的旧的和失去光泽的 2 ​​美分。

    【讨论】:

      猜你喜欢
      • 2015-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-18
      • 1970-01-01
      • 1970-01-01
      • 2021-10-23
      相关资源
      最近更新 更多