AC 数组可以隐式转换为指向其第一个元素的指针(C99:TC3 6.3.2.1 §3),即在很多情况下a
(具有 type char [100]
)的行为方式与&a[0]
(具有 type char *
)相同。这解释了为什么a
作为参数传递会起作用。
但是不要开始认为情况总是如此:数组和指针之间存在重要差异,例如关于赋值,sizeof
以及我现在想不到的其他任何东西......
&a
实际上是这些陷阱之一:这将创建一个指向数组的指针,即它具有类型char (*) [100]
(而不是 char **
)。这意味着&a
并且&a[0]
将指向相同的内存位置,但将具有不同的类型。
据我所知,这些类型之间没有隐式转换,也不保证它们也具有兼容的表示形式。我能找到的只有 C99:TC3 6.2.5 §27,它没有太多关于指向数组的指针:
[...]指向其他类型的指针不需要具有相同的表示或对齐要求。
但也有 6.3.2.3 §7:
[...]当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低寻址字节。结果的连续增量,直到对象的大小,产生指向对象剩余字节的指针。
所以演员(char *)&a
应该按预期工作。实际上,我在这里假设数组的最低寻址字节将是其第一个元素的最低寻址字节 - 不确定这是否得到保证,或者编译器是否可以自由地在数组前面添加任意填充,但是如果是这样,那就太奇怪了……
无论如何,要使其正常工作,&a
仍然必须强制转换为char *
(或void *
- 标准保证这些类型具有兼容的表示形式)。问题是除了默认参数提升之外,不会有任何转换应用于变量参数,即您必须自己显式地进行转换。
总结一下:
&a
是 类型char (*) [100]
,它可能具有与 不同的位表示char *
。因此,程序员必须进行显式转换,因为对于变量参数,编译器无法知道它应该将值转换为什么。这意味着只会进行默认参数提升,正如litb 所指出的那样,它不包括转换为void *
. 它遵循:
scanf("%s", a);
- 好的
scanf("%s", &a);
- 坏的
scanf("%s", (char *)&a);
- 应该可以