可变长度数组中的静态提示

时间:2012-08-30 21:43:34

标签: c arrays c99

我对这里的差异感到有些困惑,在C99:

int myfunc (int array[n], int n) { ... }

不会编译。据我所知,你必须首先将引用放在数组大小,所以必须写入:

int myfunc (int n, int array[n]) { ... }

但是如果你提供静态关键字,这绝对没问题:

int myfunc (int array[static 1], int n) { ... }

这个顺序对我来说是优选的,因为我习惯于在函数调用中使用数组,但为什么这可能呢?

编辑:意识到第三个例子实际上不是VLA有帮助......

作为参考,这是我正在研究的一段代码导致了这个问题:

int sum_array(int n, int m, int a[n][m])
{
  int i, j, sum = 0;
  for (i = 0; i < n; i++)
    for (j = 0; j < m; j++)
      sum += a[i][j];
  return sum;
}

5 个答案:

答案 0 :(得分:8)

原因

int myfunc (int n, int array[n]) { ... }

有效且

int myfunc (int array[n], int n) { ... }

不是由于C的词法范围规则。在范围中引入标识符之前不能使用该标识符。这个规则有一些例外,但这个规则不是其中之一。

编辑:这是C标准的相关段落:

  

(C99,6.2.1p7)“任何其他标识符的范围都在其声明者完成之后开始。”

此规则也适用于函数原型范围内的参数声明。

答案 1 :(得分:2)

已经向您解释了出错的原因:您必须在之前声明n ,您可以在其他声明中使用它。

然而,值得注意的是,这些声明中没有一个实际上声明了可变长度数组,正如您似乎相信的那样。

确实,在C99中首先允许使用[n]的语法,并且它正式是VLA声明,但在给定的上下文中,所有这些声明都将array声明为{int *的参数1}}类型,就像它一直在C89 / 90中一样。 [n]部分不是任何形式的暗示。您可以在此声明中使用[n]这一事实确实是VLA支持的副作用,但这是与VLA的任何关系结束的地方。 <{1}}被忽略了。

“提示”声明需要[n]内的关键字static。因此,您使用[]的声明等同于经典[static 1]声明(意味着int array[1]被忽略且参数具有类型1),除了它为编译器提供了一个提示至少int *元素必须存在于1指向的内存位置。

答案 2 :(得分:1)

这是因为数组必须使用常量值声明,因此您无法使用可变大小创建数组,因此无法传递具有可变大小的数组。另外,如果它只是一个单维数组,你根本不需要传入一个值,这就是传递第二个参数来告诉你数组的长度。

要使其正常工作,只需编写如下函数标题:

int myfunc (int myArray[], int n) {...}

顺序无关紧要,但是你传递的数组的大小不能变化,它必须是一个常量值。

答案 3 :(得分:1)

如果您正在使用GCC并且愿意使用他们的某些扩展程序,那么您可以在此处完成您的工作:

int myFunc (int len; /* notice the semicolon!! */ int data[len], int len)
{

}

此扩展程序的文档(可变长度数组)为here

请注意,clang由于某种原因,此扩展程序不可用,但我不太确定原因。

答案 4 :(得分:0)

编辑:Derp,范围,当然。

我的问题是;为什么你需要这样做?无论如何,你真的得到一个指针(你无法将数组传递给C中的函数,它们会降级为指针,无论函数的签名如何)。它有助于让调用者知道输入的预期大小,但除此之外它是无用的。由于他们已经超过了大小,只需使用...

int myfunc(int arr[], size_t size) {
    // ...
}

或者

int myfunc(int *arr, size_t size) {
    // ...
}