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

时间:2012-11-21 19:24:43

标签: c argv

众所周知,无法分配数组名称,如:

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

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

3 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:5)

在函数参数声明的上下文中,T a[]T a[N]都被解释为T *a;在所有三种情况下,a被声明为指针T,而不是T的数组。因此,在int main(int argc, char *argv[])中,argv实际上被声明为char **,或指向char的指针,而不是指向char的指针数组。

编辑 - 请注意,对于函数参数声明,这只是 ;对于常规变量声明,T a[N]T a[]都是将a声明为T的数组。

由于它是一个指针值,因此可以将其指定给它,并且可以递增。

除此之外,这是language standard所说的:

5.1.2.2.1程序启动

...
2如果声明它们,主函数的参数应遵循以下内容 限制:
...
- 参数argcargv以及argv数组指向的字符串应具有 由程序修改,并在程序之间保留它们最后存储的值 启动和程序终止。

修改

这是函数参数的语言:

6.7.6.3函数声明符(包括原型)

...
7参数声明为'' type ''的数组应调整为''限定指针 type '',其中类型限定符(如果有)是在[]内指定的类型 数组类型推导。如果关键字static也出现在[]内 数组类型派生,然后对每个函数调用,对应的值 实际参数应提供至少与数组一样多的数组的第一个元素的访问权限 由大小表达式指定的元素。

修改 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运算符或运算符的操作数  一元&运算符,或者是用于初始化数组的字符串文字,一个包含的表达式 类型'' type ''的数组被转换为类型为''指向 type ''指针的表达式                到数组对象的初始元素,而不是左值。如果数组对象有               注册存储类,行为未定义。

在函数main中,a1a2已被声明为int的5元素数组; a2从初始化程序中的元素数量中获取其大小。因此,表达式 a1a2具有类型“{-1}}的5元素数组”,它们可能不是赋值表达式的目标,也可能不是int++运算符的操作数。当这些表达式出现在对--的调用中时,根据上述规则,它们的类型将转换为“指向foo的指针”。因此int接收foo的指针值,而不是数组值(由数组参数转换为指针类型的规则所涵盖)。因此,a中的a表达式为foo,或指向int *的指针;因此,int可能是作业的目标,它可能是a++的操作数。

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

答案 2 :(得分:2)

main(int argc, char * argv[])

main(int argc, char **argv)

是相同且正确的。因为函数参数数组被衰减为指针

了解更多read this

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

 array = point; 
array++;

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