将多维可变长度数组传递给函数

alv*_*eko 36 c arrays c99

有很多类似的问题,但我仍然找不到任何与C99/C11中可变长度数组特征相关的答案.

如何将多维可变长度数组传递给C99/C11中的函数?

例如:

void foo(int n, int arr[][]) // <-- error here, how to fix?
{
}

void bar(int n)
{
    int arr[n][n];
    foo(n, arr);
}
Run Code Online (Sandbox Code Playgroud)

编译器(g++-4.7 -std=gnu++11)说:
error: declaration of ‘arr’ as multidimensional array must have bounds for all dimensions except the first

如果我改成它int *arr[],编译器仍抱怨:
error: cannot convert ‘int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]’ to ‘int**’ for argument ‘2’ to ‘void foo(int, int**)’

下一个问题,如何通过值传递它以及如何通过引用传递它?显然,通常你不希望在将它传递给函数时复制整个数组.

对于常量长度数组,它很简单,因为正如"常量"所暗示的那样,在声明函数时应该知道长度:

void foo2(int n, int arr[][10]) // <-- ok
{
}

void bar2()
{
    int arr[10][10];
    foo2(10, arr);
}
Run Code Online (Sandbox Code Playgroud)

我知道,将数组传递给这样的函数不是最佳实践,我根本不喜欢它.使用平面指针或对象(如std:vector)或其他方式可能更好.但是,从理论的角度来看,我有点好奇这里的答案是什么.

Kos*_*Kos 46

将数组传递给函数在C和C++中有点滑稽.没有数组类型的右值,所以你实际上传递了一个指针.

要处理2D数组(实数,不是数组数组),您需要传递2个数据块:

  • 指向它开始的指针
  • 一排有多宽

这些是两个独立的值,无论是C或C++,还是VLA或没有或什么都没有.

写一些方法:

最简单,无处不在,但需要更多的手工工作

void foo(int width, int* arr) {
    arr[x + y*width] = 5;
}
Run Code Online (Sandbox Code Playgroud)

VLA,标准C99

void foo(int width, int arr[][width]) {
    arr[x][y] = 5;
}
Run Code Online (Sandbox Code Playgroud)

VLA w /反向参数,前向参数声明(GNU C扩展)

void foo(int width; int arr[][width], int width) {
    arr[x][y]=5;
}
Run Code Online (Sandbox Code Playgroud)

C++ w/VLA(GNU C++扩展,非常难看)

void foo(int width, int* ptr) {
    typedef int arrtype[][width];
    arrtype& arr = *reinterpret_cast<arrtype*>(ptr);
    arr[x][y]=5;
}
Run Code Online (Sandbox Code Playgroud)

大话:

带有2D数组的[x] [y]表示法有效,因为数组的类型包含宽度.没有VLA =数组类型必须在编译时修复.

因此:如果你不能使用VLA,那么......

  • 没有办法在C中处理它,
  • 如果没有在C++中重载运算符重载的代理类,就无法处理它.

如果你可以使用VLA(C99或GNU C++扩展),那么......

  • 你在C的绿色,
  • 你仍然需要在C++中乱七八糟,而是使用类.

对于C++,boost::multi_array是一个不错的选择.

解决方法

对于2D阵列,您可以进行两次单独的分配:

  • 指向T(A)的一维指针数组
  • 二维数组T(B)

然后将(A)中的指针设置为指向(B)的各行.

使用此设置,您可以简单地传递(A),T**并且它将在[x][y]索引方面表现良好.

这个解决方案适用于2D,但需要越来越多的样板来实现更高的尺寸.由于额外的间接层,它也比VLA解决方案慢.

您也可能遇到类似的解决方案,每个B行都有单独的分配.在C语言中,它看起来像一个malloc-in-a-loop,类似于C++的向量向量.然而,这消除了将整个阵列放在一个块中的好处.