众所周知,数组名不能赋值,语句如下:
char * array[], * point;
array = point; /* wrong */
array++; /* wrong */
但是在main(int argc, char * argv[])
,argv++
中是可以的并且效果很好。我错过了什么?
在您的示例array
中是一个真正的数组,因此是一个不可修改的左值。在 main 中,由于它是在参数列表中声明的,argv
因此实际上是 a char **
,即可修改的指针。
这一切都归结为一个事实,这char *array[]
意味着不同的事情,这取决于上下文。
在函数参数声明的上下文中,T a[]
和T a[N]
都被解释为T *a
; 在所有三种情况下,a
都被声明为指向 的指针,T
而不是 的数组T
。因此, in int main(int argc, char *argv[])
,argv
实际上被声明为char **
,或指向指针的指针char
,而不是指向 的指针数组char
。
(编辑——请注意,这仅适用于函数参数声明;对于常规变量声明,T a[N]
并且T a[]
都声明a
为 的数组T
)。
因为它是一个指针值,所以它可以被赋值,也可以递增。
除此之外,这是语言标准必须说的:
5.1.2.2.1 程序启动
...
2 如果声明它们,主函数的参数应遵守以下约束:
...
— 参数argc
和数组argv
指向的字符串argv
应可由程序修改,并保留其最后存储的值在程序启动和程序终止之间。
编辑
这是函数参数的语言:
6.7.6.3 函数声明器(包括原型)
...
7 将参数声明为“类型数组”应调整为“指向 类型的限定指针”,其中类型限定符(如果有)是在数组类型派生的[
and中指定的那些。]
如果关键字static
也出现在数组类型派生的[
and]
中,那么对于函数的每次调用,对应的实际参数的值应提供对数组的第一个元素的访问,该数组的元素至少与大小指定的一样多表达。
编辑2
一些示例(假设 C99 编译器):
void foo(int a[], size_t len)
{
size_t i;
printf("sizeof a = %zu\n", sizeof a);
printf("sizeof (int *) = %zu\n", sizeof (int *));
for (i = 0; i < len; i++)
printf("a[%zu] = %d\n", i, *a++);
}
int main(void)
{
int a1[5] = {0};
int a2[] = {0, 1, 2, 3, 4};
printf("sizeof a1 = %zu\n", sizeof a1);
printf("sizeof a2 = %zu\n", sizeof a2);
foo(a1, sizeof a1 / sizeof a1[0]);
foo(a2, sizeof a2 / sizeof a2[0]);
return 0;
}
再来一篇标准话:
6.3.2.1 左值、数组和函数指示符
...
3 除非它是运算sizeof
符、运算符_Alignof
或一元&
运算符的操作数,或者是用于初始化数组的字符串文字,否则类型为 ''array of type '' 的表达式将转换为表达式类型 ''pointer to type '' 指向数组对象的初始元素并且不是左值。如果数组对象具有寄存器存储类,则行为未定义。
在函数main
中,a1
和a2
已被声明为 ; 的 5 元素数组int
。a2
从初始值设定项中的元素数量获取其大小。表达式 因此具有“5 元素数组”类型a1
,它们可能不是赋值表达式的目标,也可能不是or运算符的操作数。当这些表达式出现在对 的调用中时,它们的类型将根据上述规则转换为“指向的指针”。因此接收一个指针值,而不是一个数组值,for (这被说数组参数转换为指针类型的规则所涵盖)。所以表达式有类型,或者指向a2
int
++
--
foo
int
foo
a
a
foo
int *
int
; 因此,a
可能是赋值的目标,也可能是++
and的操作数--
。
还有一个区别:根据上面引用的规则,当数组表达式是运算符的操作数时,不会sizeof
发生指针类型的转换;sizeof a1
应评估为数组占用的字节数a1
(5 * sizeof int
)。但是,由于a
infoo
具有 type int *
, not int [5]
,sizeof a
应该只计算指向int
(sizeof (int *)
) 的指针的字节数。
main(int argc, char * argv[])
或者
main(int argc, char **argv)
相同且正确。因为在函数参数数组中衰减为指针
有关更多信息,请阅读此
但是您显示的代码是实际的数组。数组的名称给出了第一个元素的地址,它是不可修改的,这就是这样做的原因:
array = point;
array++;
是错误的,因为您已经提到过。