函数原型和块代码中的变量声明:区别?

Variable declaration in function prototype and in block code : difference?

为什么 int array[] 在 main 而不是在函数原型中引发编译错误? 这是否意味着在函数原型中总是写 int * array 更好?

void myfoo (int array[]) { // No compilation error
;}

void myfoo1 (int *array1) { // No compilation error
;}

int main() {
    int array[]; // Compilation error
    int* array1; // No compilation error
}

在您的代码中,在函数内部,为数组定义编写 int array[]; 是语义错误。

在这种情况下,array 是一个没有链接的变量,("块作用域 不使用 storage-class 说明符 extern") 且根据规范声明的对象的标识符:

If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end of its declarator, [....]

一个空的 [](中间有或没有 space(s)),不能构成一个有效的数组定义结构,因为数组的大小仍然未知(注意也缺少显式的大括号括起来的初始化列表)。因此,您的编译器会抱怨,因为类型不完整并且它不知道为该数组变量保留的内存总量。

另一方面,对于函数参数,数组类型参数实际上会衰减为指向该类型的指针,因此,指定数组大小不是强制性的。引用章节 §6.7.6.3

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. [...]

If the function declarator is not part of a definition of that function, parameters may have incomplete type and may use the [*] notation in their sequences of declarator specifiers to specify variable length array types.

所以,基本上,一个声明

 void myfoo (int array[])

等同于

void myfoo (int *array)

所以,这被编译器接受了。

void myfoo (int array[]) { // No compilation error
;}

这意味着将使用整数数组(任意大小)调用 myfoo()。编译器直接编译即可。

void myfoo1 (int *array1) { // No compilation error
;}

这意味着将使用指向整数的指针调用 myfoo1()。编译器直接编译即可。

int main() {
    int array[]; // Compilation error
    int* array1; // No compilation error
}

int array[];

这是数组的定义。但是编译器无法确定数组的大小。所以它不知道要分配多少内存。 所以你必须提供大小或用下面的一些值初始化它。

int array[3];

int array[] = {1,2,1};

.

int* array1;

这只是整型指针的声明。没什么问题,编译器可以编译它。

从根本上说,main 块内的数组声明需要大小而函数参数中的数组声明不需要的原因是 main 中的声明是 定义一个数组,而函数参数只是接收一个由其他东西定义的数组。

因此 main 中的定义需要一个大小,因为它必须为数组保留存储空间。

函数参数只是接收一个数组,所以只需要知道数组从哪里开始就可以了。它不需要知道大小。 (也就是说,编译器不需要知道大小就可以编译代码。函数可能需要知道大小才能执行其预期目的,但这是程序员的事,而不是编译器的事。)

由于 C 规则,数组实际上永远不能作为函数参数传递。每当将数组作为函数参数给出时,编译器会自动将其转换为指向其第一个元素的指针。同样,函数参数可以是指针,但实际上不能是数组。当您将函数参数声明为数组时,编译器会自动将其调整为声明指针。所以函数声明void myfoo(int array[])自动调整为void myfoo(int *array).

要求main中的声明有大小的具体规则是C 2018 6.7 7:

If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end of its declarator, or by the end of its init-declarator if it has an initializer;…