7

众所周知,数组名不能赋值,语句如下:

char * array[], * point;
array = point; /* wrong */
array++; /* wrong */

但是在main(int argc, char * argv[]),argv++中是可以的并且效果很好。我错过了什么?

4

3 回答 3

6

在您的示例array中是一个真正的数组,因此是一个不可修改的左值。在 main 中,由于它是在参数列表中声明的,argv因此实际上是 a char **,即可修改的指针。

这一切都归结为一个事实,这char *array[]意味着不同的事情,这取决于上下文。

于 2012-11-21T19:26:51.060 回答
5

在函数参数声明的上下文中,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中,a1a2已被声明为 ; 的 5 元素数组inta2从初始值设定项中的元素数量获取其大小。表达式 因此具有“5 元素数组”类型a1,它们可能不是赋值表达式的目标,也可能不是or运算符的操作数。当这些表达式出现在对 的调用中时,它们的类型将根据上述规则转换为“指向的指针”。因此接收一个指针值,而不是一个数组值,for (这被说数组参数转换为指针类型的规则所涵盖)。所以表达式有类型,或者指向a2int++--foointfooaafooint *int; 因此,a可能是赋值的目标,也可能是++and的操作数--

还有一个区别:根据上面引用的规则,当数组表达式是运算符的操作数时,不会sizeof发生指针类型的转换;sizeof a1应评估为数组占用的字节数a1(5 * sizeof int)。但是,由于ainfoo具有 type int *, not int [5]sizeof a应该只计算指向int(sizeof (int *)) 的指针的字节数。

于 2012-11-21T19:49:19.150 回答
2
main(int argc, char * argv[])

或者

main(int argc, char **argv)

相同且正确。因为在函数参数数组中衰减为指针

有关更多信息,请阅读此

但是您显示的代码是实际的数组。数组的名称给出了第一个元素的地址,它是不可修改的,这就是这样做的原因:

 array = point; 
array++;

是错误的,因为您已经提到过。

于 2012-11-21T19:39:00.227 回答