众所周知,数组名称不能分配,句子如:
char * array[], * point;
array = point; /* wrong */
array++; /* wrong */
Run Code Online (Sandbox Code Playgroud)
但是main(int argc, char * argv[]),argv++好的,运作良好.我错过了什么?
在您的示例中array是一个真正的数组,因此是一个不可修改的l值.在main中,因为它在参数列表中声明,argv实际上是一个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的参数为""的阵列的声明类型 "",应调整至""合格音响编指针 键入 "",其中类型合格音响ERS(如果有的话)内的那些SPECI音响ED[和]数组类型派生的.如果关键字static也内出现[和]在阵列类型派生的,那么对于每个调用函数,相应的实际参数的值应提供大小访问与至少一样多的元素SPECI音响ED阵列的第一个元件表达.
编辑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;
}
Run Code Online (Sandbox Code Playgroud)
还有一个标准:
6.3.2.1左值,数组和函数指示符
...
3除了当它是的操作数sizeof运算符,_Alignof操作者,或一元&运算符,或者是用于初始化数组文本的字符串,其具有输入""的阵列的表达类型 ""被转换为表达式用类型""指针键入指向阵列对象的初始元素,不是左值"".如果数组对象具有寄存器存储类,则行为未定义.
在功能方面main,a1并且a2已被定义为5-元件阵列int; a2从初始化程序中的元素数量中获取其大小.的表达 a1和a2因此具有类型"的5个元素的数组int的赋值表达式,并且它们可以不是目标",也不得是操作数的++或--运营商.当这些表达式出现在调用中时foo,它们的类型将int根据上述规则转换为"指向".因此foo接收指针值,而不是数组值a(由数组参数转换为指针类型的规则所涵盖).所以表达式a中foo有has类型int *或指针int; 因此,a可以是赋值的目标,并且它可以是一个操作数++和--.
还有一个区别:根据上面引用的规则,当数组表达式是运算符的操作数时,不会转换为指针类型sizeof; sizeof a1应该评估数组占用的字节数a1(5*sizeof int).但是,由于a在foo有一个类型int *,而不是int [5],sizeof a应该只评价为字节的一个指针的数量int(的sizeof (int *)).