为什么可以分配数组名称argv?

Lia*_*gyu 7 c argv

众所周知,数组名称不能分配,句子如:

char * array[], * point;
array = point; /* wrong */
array++; /* wrong */
Run Code Online (Sandbox Code Playgroud)

但是main(int argc, char * argv[]),argv++好的,运作良好.我错过了什么?

cni*_*tar 6

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

这一切都归结为这char *array[]意味着不同的事情,取决于具体情况.


Joh*_*ode 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如果他们宣布,该参数的主要功能应遵循以下限制:
...
-参数argcargv和串指向的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从初始化程序中的元素数量中获取其大小.的表达 a1a2因此具有类型"的5个元素的数组int的赋值表达式,并且它们可以不是目标",也不得是操作数的++--运营商.当这些表达式出现在调用中时foo,它们的类型将int根据上述规则转换为"指向".因此foo接收指针值,而不是数组值a(由数组参数转换为指针类型的规则所涵盖).所以表达式afoo有has类型int *或指针int; 因此,a可以是赋值的目标,并且它可以是一个操作数++--.

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