有很多类似的问题,但我仍然找不到任何与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);
}
编译器(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);
}
我知道,将数组传递给这样的函数并不是最佳实践,我根本不喜欢它。使用平面指针或对象(如std:vector)或其他方式可能更好。但是,从理论的角度来看,我有点好奇这里的答案是什么。
答案 0 :(得分:43)
将数组传递给函数在C和C ++中有点滑稽。没有数组类型的右值,所以你实际上是在传递一个指针。
要处理2D数组(实数,不是数组数组),您需要传递2个数据块:
这些是两个独立的值,无论是C或C ++还是VLA或没有或什么都不是。
最简单,无处不在,但需要更多的手工工作
void foo(int width, int* arr) {
arr[x + y*width] = 5;
}
VLA,标准C99
void foo(int width, int arr[][width]) {
arr[x][y] = 5;
}
VLA w /反向参数,前向参数声明(GNU C扩展名)
void foo(int width; int arr[][width], int width) {
arr[x][y]=5;
}
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;
}
带有2D数组的[x] [y]表示法有效,因为数组的类型包含宽度。没有VLA =数组类型必须在编译时修复。
因此:如果你不能使用VLA,那么......
如果您可以使用VLA(C99或GNU 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 ++的向量向量。然而,这消除了将整个阵列放在一个块中的好处。
答案 1 :(得分:1)
没有明确的方法可以做到这一点,但你可以使用一种解决方法将二维数组视为一维数组,然后将其重新转换为函数内的二维数组。
void foo2(int n, int *arr)
{
int *ptr; // use this as a marker to go to next block
int i;
int j;
for(i = 0; i < n; i++)
{
ptr = arr + i*n; // this is the starting for arr[i] ...
for (j = 0; j < n ;j++)
{
printf(" %d ", ptr[j]); // This is same as arr[i][j]
}
}
}
void bar2()
{
int arr[10][10];
foo2(10, (int *)arr);
}