要记住的几件事:
当您将数组表达式作为参数传递给函数时,它将从“N-element array of T
”类型的表达式转换为“pointer to T
”,表达式的值将是第一个元素的地址数组。被调用函数接收一个指针值。
[]
运算符可以与数组或指针类型的表达式一起使用;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]
?请记住,在将数组表达式作为参数传递时,数组表达式的类型从“N-element array of T
”转换为“pointer to T
”。在本例中,T
是“ cols
-element array of int
”,所以我们从“ -element rows
array of cols
-element aray of int
”变为“pointer to - cols
element array of int
”。在函数参数声明的上下文中T a[N]
,T a[]
、 和T *a
都是相同的;在所有三种情况下,都a
被声明为指向. T
Soint (*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
,也不能在函数之外定义。他们不能使用{}
-style 初始化语法。此外,从 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
.