当在函数中使用可变长度数组作为参数时
int sum(int n, int a[n]);
很容易理解第一个参数(n
)指定了第二个参数(a
)的长度。但是当遇到另一种用作可变长度数组参数的原型时,就会遇到问题。
int sum(int n, int a[*]);
为什么在[]
中使用*
而不是n
真的很难理解?
当在函数中使用可变长度数组作为参数时
int sum(int n, int a[n]);
很容易理解第一个参数(n
)指定了第二个参数(a
)的长度。但是当遇到另一种用作可变长度数组参数的原型时,就会遇到问题。
int sum(int n, int a[*]);
为什么在[]
中使用*
而不是n
真的很难理解?
[*]
语法用于声明函数原型。关键细节在于,在函数原型中,您不需要为参数命名,只需指定每个参数的类型。n
。但是,在许多情况下,您需要告诉编译器某些参数是VLA。这是[*]
语法发挥作用的时候。int sum(int, int [*]);
然而,需要注意的是,在你自己的特定示例中,这种语法是合法的,但并不是完全必要的。就像对于非VLA数组一样,int [n]
参数仍然等同于int *
参数(即使对于非常量的n
)。这意味着您可以将函数原型简单地定义为:
void functionName(int *array, int n);
int sum(int, int []);
或作为
int sum(int, int *);
原型仍然能够完成其目的,即它将正确匹配函数定义。换句话说,一个声明为1D数组的参数的VLA属性完全没有影响,因此在这种情况下不真正需要使用[*]
特性。
[*]
在类型的"可变数组性"没有丢失的情况下变得重要,这种情况出现在2D VLA(或指向VLA的指针)中。例如,定义为
int sum2d(int n, int m, int a[n][m])
{
...
}
可能被原型化为以下任何一种
int sum2d(int, int, int a[*][*]);
int sum2d(int n, int, int a[n][*]);
int sum2d(int, int m, int a[*][m]);
int sum2d(int n, int m, int a[n][m]);
以上所有的原型都与函数定义相匹配。
当然,如果您有始终命名函数原型中所有参数的习惯,那么您将永远不需要使用此[*]
语法,因为您将能够使用上述列表中的最后一个原型。
P.S. 同所有参数声明中的数组一样,第一个[]
总是无关紧要的并且总是会衰减为指针,这意味着以下也是针对上述sum2d
有效的等效原型声明。
int sum2d(int, int, int a[][*]);
int sum2d(int, int, int (*a)[*]);
int sum2d(int n, int m, int (*a)[m]);
重要的是第二个[]
,它必须声明为“可变长度”。
[]
总是丢失的事实。该参数会衰变为指针。这适用于所有数组参数声明,无论它们是否为VLA。 (我在答案中已经说明了这一点)。在C中,“注入”永久的非消失性数组特性的唯一方法是将其作为指向数组的指针,例如int(* p)[5]
或int(* p)[n]
。在参数声明中,这等同于2D数组声明。 - AnT stands with Russiaint arr[n][m]
,编译器需要知道大小 m
,因为在像 arr[2][3]
这样的数组访问中,它必须内部转换为类似于 *(arr + 2 * m + 3)
的东西(注意表达式中的 m
)。在 ANSI C 中,您唯一的选择是传递 int *arr
并手动执行 *(arr + 1 * m + 1)
部分,但在 C99 中,您可以让编译器为您处理,因此有了新的语法。第一个大小(在本例中为 n
)从未被需要,因为它们的元素总是紧挨着彼此(在这种情况下为 sizeof int
字节)。 - yynytest.c:3: error: ‘[*]’ not allowed in other than function prototype scope
。经过一些调查,这实际上是一种在函数原型中声明VLA的方法,使用星号代替变量名。VLA。问题在于,如果您将变量放入VLA而不是星号,它将告诉您该变量未声明,因此星号是c99内置的解决方法。int arr[N];
指向整数的指针数组:int *arr[N];
- 指向整数数组的指针:int (*ptr)[N]
,可变长度数组:int arr[<非常量表达式>];
- 函数参数列表中的VLA:与之前相同或 int arg[*];
- user529758
[*]
是非常有用的。 - ajp15243