要记住的几件事:
当您将数组表达式作为参数传递给函数时,它将从类型为“T 的 N 元素数组”类型的表达式转换为“指向 @ 的指针” 987654322@",表达式的值将是数组第一个元素的地址。被调用函数接收一个指针值。
[] 运算符可用于数组或指针类型的表达式; IOW,给定声明int a[10]; int *p = a;,那么p[i] 和a[i] 指的是同一个元素。
在声明接受 VLA 作为参数的函数时,您必须在声明数组之前声明指定维度的参数。
所以,对于一个操作 2D VLA 的函数,你应该写类似
void foo( size_t rows, size_t cols, int (*multiarray)[cols] ) // or multiarray[][cols]
{
size_t i, j;
for ( i = 0; i < rows; i++ )
for ( j = 0; j < cols; j++ )
multiarray[i][j] = some_value();
}
int (*multiarray)[cols] 怎么了?请记住,在将数组表达式作为参数传递时,数组表达式的类型从“T 的 N 元素数组”转换为“指向 T 的指针”。在这种情况下,T 是“cols-int 的元素数组”,所以我们要从“rows-cols-int 的元素数组”到“指向cols-int" 的元素数组。在函数参数声明的上下文中,T a[N]、T a[] 和 T *a 都是相同的;在所有三种情况下,a 都被声明为指向T 的指针。所以int (*multiarray)[cols]等价于int multiarray[][cols],也就是等价于int multiarray[rows][cols]。我更喜欢使用第一种形式,因为它最准确地代表了情况。
如果你想将此数组作为参数传递给另一个函数,你会使用相同的类型:
void bar( size_t rows, size_t cols, int (*multiarray)[cols] )
{
foo( rows, cols, multiarray );
}
int main( void )
{
size_t rows = 0;
size_t cols = 0;
// you must assign values to rows and cols before declaring a VLA with them
rows = ...;
cols = ...;
int arr[rows][cols];
bar( rows, cols, arr );
...
}
在foo 中对数组内容所做的任何更改都将反映在bar 和main 中。
VLA 很有用,但也有其局限性。它们不能声明为static,也不能在函数之外定义。他们不能使用{} 风格的初始化语法。此外,从 2011 年标准开始,VLA 支持现在是可选,因此您不能依赖它们在任何地方都得到支持。
如果您没有可用的 VLA 并且您的数组大小直到运行时才知道,您将不得不使用动态内存分配(malloc 或 calloc),以及您传递给您的类型功能会有所不同:
void foo( size_t rows, size_t cols, int **multiarray )
{
size_t i, j;
for ( i = 0; i < rows; i++ )
for ( j = 0; j < cols; j++ )
multiarray[i][j] = some_value();
}
void bar( size_t rows, size_t cols, int **multiarray )
{
foo( rows, cols, multiarray );
}
int main( void )
{
size_t rows;
size_t cols;
int **multiarray = NULL;
... // get rows and cols
// allocate memory for pointers to each row
multiarray = malloc( sizeof *multiarray * rows );
if ( multiarray )
{
size_t i;
// allocate each row
for ( i = 0; i < rows; i++ )
{
multiarray[i] = malloc( sizeof *multiarray[i] * cols );
if ( !multiarray[i] )
break;
}
if ( i < rows )
{
// malloc failed for one of the multiarray rows; we need to
// free whatever memory has already been allocated and exit
while ( i-- )
free( multiarray[i] );
free( multiarray );
exit(0);
}
}
bar ( rows, cols, multiarray );
...
if ( multiarray )
{
size_t i;
for ( i = 0; i < rows; i++ )
free( multiarray[i] );
free( multiarray );
}
}
这种方法的一个缺点是分配的内存不能保证是连续的(即,行在内存中不会相邻)。如果这很重要,您将不得不采用另一种方法。您无需单独分配行和列,而是将所有内容分配在一个块中,并手动映射数组索引:
void foo( size_t rows, size_t cols, int *fakemultiarray )
{
size_t i, j;
for ( i = 0; i < rows; i++ )
for ( j = 0; j < rows; j++ )
fakemultiarray[ i * rows + j ] = some_value();
}
void bar( size_t rows, size_t cols, int *fakemultiarray )
{
foo( rows, cols, fakemultiarray );
}
int main( void )
{
size_t rows;
size_t cols;
int *fakemultiarray = NULL;
... // get rows and cols
fakemultiarray = malloc( sizeof *fakemultiarray * rows * cols );
if ( fakemultiarray )
bar( rows, cols, fakemultiarray );
...
free( fakemultiarray );
}
在这种情况下,我们为所有元素分配了一个足够大的缓冲区,但我们必须将其索引为一维数组,将索引计算为i * rows + j。