35

在函数中使用可变长度数组作为参数时

int sum(int n, int a[n]);

很容易理解第一个参数(n)指定第二个参数()的长度a。但是遇到了另一个用于VLA作为参数 的原型

int sum(int n, int a[*]);

真的很难理解,为什么里面*用的是代替?n[]

4

2 回答 2

52

[*]语法旨在在声明函数原型时使用。这里的关键细节是在函数原型中你不需要命名参数,你只需要指定每个参数的类型。

在您的示例中,如果您将第一个参数保留为unnamed,那么显然您将无法n在第二个(数组)参数声明中使用。然而,在许多情况下,您必须告诉编译器某些参数是 VLA。这时候[*]语法就派上用场了。

在您的情况下,如果您省略参数名称,原型可能看起来像

int sum(int, int [*]);

但是,重要的是要注意,在您的特定示例中,此语法是合法的,但并非完全必要。就像非 VLA 数组一样,int [n]参数仍然等同于int *参数(即使对于非常量n)。这意味着您可以简单地将您的功能原型化为

int sum(int, int []);

或作为

int sum(int, int *);

并且原型仍将发挥其作用,即它将正确匹配函数定义。换句话说,声明为一维数组的参数的 VLA 属性完全无关紧要,并且[*]此类 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]);

以上所有原型都与函数定义正确匹配。

当然,如果你有在函数原型中总是命名所有参数的习惯,那么你将永远不需要这种[*]语法,因为你将能够使用上面列表中的最后一个原型。

PS 同样,与参数声明中的所有数组一样,第一个[]总是无关紧要的并且总是衰减为指针,这意味着以下也是上述的有效等效原型声明sum2d

    int sum2d(int, int, int a[][*]);
    int sum2d(int, int, int (*a)[*]);
    int sum2d(int n, int m, int (*a)[m]);

这是第二个[]真正重要的,必须声明为“可变长度”。

于 2013-06-28T19:07:08.583 回答
4

当您将星号放在实际功能中时,它会出现此错误test.c:3: error: ‘[*]’ not allowed in other than function prototype scope。经过一番研究,这实际上是一种在函数原型中声明 VLA 的方法,用*代替变量名。极简主义
这里的问题是,如果你为 VLA 放置一个变量而不是星号,它会告诉你它是未声明的,所以星号是 c99 内置的一种解决方法。

于 2013-06-28T18:54:52.973 回答