【问题标题】:How to dynamically allocate a 2d array and why?如何动态分配二维数组,为什么?
【发布时间】:2014-10-06 20:27:06
【问题描述】:

对于我的任务,我必须在程序中做的一件事是动态分配一个二维数组。 我不知道该怎么做或为什么。

这就是我现在所拥有的。

   size = atoi(argv[1]);
   int Pond[size][size];
   int i, j;
   for(i = 0; i < size; i ++){
      for(j = 0; j < size; j++){
        Pond[i][j]=0;
      }
   }

我找到了这样做的答案,但我不知道如何访问每一列或每一行。

int **Pond;
Pond = (int**)malloc(size * sizeof(int*));
for (i = 0; i < size; i++) {
    Pond[i] = (int *) malloc(size * sizeof(int));

【问题讨论】:

    标签: c arrays pointers multidimensional-array int


    【解决方案1】:

    正确使用 C 强大的数组类型语法如下所示:

    int (*Pond)[size] = malloc(size * sizeof(*Pond));
    

    分配就是这样。之后,Pond 中的元素可以像这样简单地访问:

    for(int y = 0; y < size; y++) {
        for(int x = 0; x < size; x++) {
            Pond[y][x] = 0;
        }
    }
    

    当然还有释放:

    free(Pond);
    

    它并没有变得更简单。

    【讨论】:

    • +1 请注意,这需要 C99 编译器,因为 size 不是常量表达式。如果大小相当小,那么即使只是 int Pond[size][size]; 就足够了。
    • 谢谢!这就是我一直在寻找的解决方案。你能告诉我为什么我必须动态分配吗?到目前为止,代码在没有 malloc 的情况下工作。数组不会在程序中改变大小。它确实将数组传递给另一个函数,这就是我需要 malloc 的原因吗?
    • 对不起,我的评论发错了。它已被删除。
    • @Asmyldof why 您想要这样做的一个重要原因是,如果您尝试将大型数组创建为基于堆栈的对象。堆栈的大小通常非常有限(有时大约为一兆字节或两兆字节)。尝试在函数内创建一个 2000 x 2000 的大型整数数组(未使用 static 属性定义)。在大多数平台上,它可能会在运行时失败,因为堆栈会溢出。
    • @MichaelPetch 很公平,我假设这个问题的意思是“我为什么不对我使用的所有编译器做一个全局/静态的”女巫优先堆。无论如何,你是对的,如果不破坏堆栈,它会造成严重混乱的危险。虽然我要在尽可能多的“恢复出厂设置”系统上尝试一下,看看下周末的最终分数是多少:-)
    【解决方案2】:

    [] 运算符处理指针的方式与处理数组表达式的方式几乎相同,因此无论您如何分配,您都可以使用 Pond[i][j] 访问特定元素(除非您将其分配为一维数组dom0 显示)。

    如果在编译时知道行数和列数,这是最简单的:

    #define M ... // rows
    #define N ... // columns
    
    int (*Pond)[N] = malloc ( sizeof *Pond * M);
    ...
    Pond[i][j] = x;
    ...
    free( Pond );
    

    变量Pond类型是“指向N的指针-int的元素数组”。 表达式 *Pond 的类型是“int 的 N 元素数组”。所以sizeof *Pond 给了我们N-element 数组int 中的字节数;我们将其乘以M 以获得数组所需的总字节数。

    由于a[i] 被评估为*(a + i)[] 运算符在指针表达式上的工作方式与在数组表达式上的工作方式相同1;也就是说,您可以在这里使用Pond[i][j],就像使用常规二维数组一样。

    如果在运行时才知道行数和列数,但是您使用的是支持可变长度数组的 C99 编译器或 C2011 编译器,则几乎相同: p>

    size_t n, m;
    /**
     * get values of n and m
     */
    int (*Pond)[n] = malloc( sizeof *Pond * m );
    ...
    Pond[i][j] = x;
    ...
    free( Pond );
    

    与上述相同,只是 mn 直到运行时才知道。在这两种情况下,动态分配的数组都是连续的(所有行在内存中都是相邻的)。

                    +---+
              Pond: |   | ---+
                    +---+    |
                     ...     |
                    +---+    |
        Pond[0][0]: |   | <--+
                    +---+
        Pond[0][1]: |   |
                    +---+
                     ...
                    +---+
      Pond[0][n-1]: |   |
                    +---+
        Pond[1][0]: |   |
                    +---+
        Pond[1][1]: |   |
                    +---+
                     ...
                    +---+
      Pond[m-1][0]: |   |
                    +---+
      Pond[m-1][1]: |   |
                    +---+
                     ...
                    +---+
    Pond[m-1][n-1]: |   |
                    +---+
    

    如果直到运行时才知道行数和列数,并且您使用的编译器不支持 VLA,则您有两种选择,具体取决于您是否希望数组是连续的。

    如果数组不必连续,可以使用两步分配方法:

    size_t n, m;
    /**
     * get values for n and m
     */
    int **Pond = malloc( sizeof *Pond * m ); // allocate m rows of pointer to int
    if ( Pond )
    {
      for ( size_t i = 0; i < m; i++ )
      {
        Pond[i] = malloc( sizeof *Pond[i] * n ); // allocate n columns of int for each row
      }
    }
    

    在这种情况下,Pond 是指向int 的指针;它将最终指向一个有效的一维指针数组,指向int;这些指针中的每一个都将指向int 的一维数组,类似于以下内容:

                  +---+
            Pond: |   | ---+
                  +---+    |
                           |
                    +------+
                    |
                    V  
                  +---+          
         Pond[0]: |   | ------------+ 
                  +---+             |
         Pond[1]: |   | ---------+  |
                  +---+          |  |
         Pond[2]: |   |          |  |  
                  +---+          |  |
                   ...           |  |
                  +---+          |  |
       Pond[m-1]: |   |          |  | 
                  +---+          |  |
                                 |  |
                  +---+          |  |
      Pond[0][0]: |   | <--------|--+
                  +---+          |
      Pond[0][1]: |   |          |
                  +---+          |
                   ...           |
                  +---+          |
    Pond[0][n-1]: |   |          |
                  +---+          |
                                 |
                  +---+          |
      Pond[1][0]: |   | <--------+
                  +---+
      Pond[1][1]: |   |
                  +---+
                   ...
                  +---+
    Pond[1][n-1]: |   |
                  +---+
    

    但是因为Pond[i][j] 被评估为*(*(Pond + i) + j),所以它仍然有效。

    请注意,由于这是一个两步分配过程,释放也需要两个步骤:

    for ( size_t i = 0; i < m; i++ )
      free( Pond[i] );
    free( Pond );
    

    如果数组确实需要连续,那么您必须将内存分配为一维数组并手动计算索引:

    int *Pond = malloc( sizeof *Pond * m * n );
    ...
    Pond[ i * m + j ] = x;
    ...
    free( Pond );
    


    1。在大多数情况下,数组表达式将被转换或“衰减”为指针表达式,因此下标实际上是对指针表达式起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-03
      • 2013-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多