【问题标题】:Passing multidimensional array to a function C将多维数组传递给函数 C
【发布时间】:2011-01-20 01:47:06
【问题描述】:

我在将多维数组传递给 C 中的函数时遇到问题。无论是 typedef 还是参数应该是什么。

目前,我的函数 def 如下所示:

int foo(char *a, char b[][7], int first_dimension_of_array);

我这样声明一个数组:

char multi_D_array[20][7];

当我尝试这样调用函数时:

foo(d, multi_D_array, 20);

我收到警告,该函数的第二个参数来自不兼容的指针类型。我已经尝试了许多我在网上看到的变体,但仍然无法正确。此外,当使用 GDB 时,我发现只有二维数组的第一个数组被传入。如果我做错了什么,我们将不胜感激。

【问题讨论】:

  • 尝试传递一个指向数组的指针

标签: c multidimensional-array


【解决方案1】:

大警告:我通常不会以这种方式处理多维数组。

我试过这个只是为了检查,但是这个:

#include <stdio.h>

int foo(char b[][7])
{
    printf("%d\n", b[3][4]);
    return 0;
}

int main(int argc, char** argv)
{
    char multi_d_arr[20][7];
    multi_d_arr[3][4] = 42;
    foo(multi_d_arr);
    return 0;
}

使用gcc -Wall 编译和运行没有任何问题。老实说,我不确定第二个参数如何被视为不兼容的指针类型。工作正常。

但是,既然您问了,我将如何处理二维数组?更好的方法是使用这样的指针:

char** array2d = malloc((MAX_i+1)*sizeof(char*));
for ( i = 0; i < (MAX_i+1); i++ )
{
    array2d[i] = malloc((MAX_j+1)*sizeof(char));
}

现在,为了清楚起见,您可以访问的最大元素是 array2d[MAX_i][MAX_j]

完成后不要忘记反转过程:

for ( i = 0; i < (MAX_i+1); i++ )
{
    free(array2d[i]);
}
free(array2d);

现在,使用这种方法,下标符号仍然有效,所以array2d[x][y] 仍然可以访问正确的值。从字面上看,array2d 是一个指针数组,每个 array2d[i] 也是如此。

为什么这是一个更好的方法?好吧,如果您愿意,您可以拥有可变大小的子数组。您所要做的就是更改 for 循环。这种技术通常用于字符串数组,特别是在应用程序的int main(int argc, char** argv) 签名中。 argv 是一个可变长度字符串数组。使用strlen() 确定它们的长度。

你能把这个传过去吗?当然。对于初学者,您刚刚在 main 中收到它,但您也可以像这样编写函数签名:

int foo(char** ar2d, const unsigned int size);

然后调用它:

char** somearray;
/* initialisation of the above */

foo(ar2d, thesizeofar2d);

/* when done, free somearray appropriately */

需要明确的是,您包含尺寸参数的方法(如const unsigned int size)是非常好的做法,您应该坚持下去。

【讨论】:

  • 您可以使用 C99 可变长度数组做得更好,并根据其运行时大小声明数组的类型。你的建议真的是坏主意。如果子数组改变大小,您必须保持每一行的大小(或者如果它改变大小,则有访问外部未分配子数组的风险)。这意味着分配具有长度和指向数据的指针以及更复杂语法的结构。如果每个子数组的大小相同,那么使用一个 malloc 只分配一块内存会更高效、更易于阅读且不易出错。
  • 澄清一下,我的意思是当子数组是字符串时,问题完全不同,因为零终止符隐含地给出子数组大小(字符串大小)并避免将其保持在结构中。此外,您经常希望存储指向静态分配的字符串的指针。这个用例是唯一的好用例,你不应该从中概括。
【解决方案2】:

您在问题中给出的声明和函数调用是完全正确的 C,并且没有使用 gcc 发出警告。

你确定你完全复制了有问题的代码吗?

【讨论】:

    【解决方案3】:

    嗯,它在定义上是不兼容的。

    char[20][7]char[][7]不一样

    只是摆脱警告。

    并且它没有传递“仅传递二维数组的第一个数组”,它仅传递一个指向数组的指针(指向第一个元素的指针,或指向数组的开头)。 您只能看到 GDB 中的前 7 个元素,因为根据函数内部数组的类型,GDB 只知道 7 个元素。

    【讨论】:

    • 它们是兼容的。数组multi_D_array,在函数调用上下文中使用时,被转换为指向其第一个元素的指针,其类型为char (*)[7]。参数char [][7] 正是这种类型。
    【解决方案4】:

    您的代码适合我吗?这是我的测试代码:http://codepad.org/wSppLiwl

    【讨论】:

      【解决方案5】:

      从 C99 开始,您可以拥有可变长度数组并执行以下操作。基本上为维度数组提供的参数用于声明数组大小。这很可能是现代编译器的最佳方法。

      #include <stdio.h>
      
      int foo(char *a, int fdim, char b[fdim][7]){
      
          printf("b[19][6] = %d\n", b[19][6]);
          return 0;
      }
      
      int main(){
          char d[10];
          char multi_D_array[20][7];
          int x, y;
      
          for (x = 0 ; x < 7 ; ++x){
              for (y=0 ; y < 20 ; ++y){
                  multi_D_array[y][x] = y + x;
              }
          }
          foo(d, 20, multi_D_array);
      }
      

      即使它也适用于 C++,您也可以通过阅读我的回答 therethere(当然还有其他人的回答)来更好地理解 C 数组。

      【讨论】:

      • 正确,只是对于第一个维度,这并没有改变。您的声明完全等同于 OP 给出的声明(但转换位置)。只有从第二维 VLA 开始,作为函数参数才会带来新的东西。
      【解决方案6】:

      底线是 C/C++ 不能很好地处理多维数组。大多数情况下,将其设置为一维数组并自己进行行列寻址会更容易。

      【讨论】:

        猜你喜欢
        • 2014-01-15
        • 2014-11-19
        • 2014-03-16
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多