【问题标题】:Why the array name argv can be assigned?为什么可以分配数组名argv?
【发布时间】:2012-11-23 00:48:15
【问题描述】:

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

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

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

【问题讨论】:

  • 我不知道数组参数以这种方式降级为指针。感谢您提出问题!

标签: c argv


【解决方案1】:

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

这一切都归结为char *array[] 的含义不同,具体取决于上下文。

【讨论】:

    【解决方案2】:

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

    (edit -- 请注意,对于函数参数声明是正确的;对于常规变量声明,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 运算符或 一元 &amp; 运算符,或者是用于初始化数组的字符串文字,该表达式具有 type ‘‘array of type’’ 被转换为类型为 ‘‘pointer to type’’ 的表达式,它指向 到数组对象的初始元素并且不是左值。如果数组对象有 注册存储类,行为未定义。

    在函数main中,a1a2被声明为int的5元素数组; a2 从初始值设定项中的元素数获取其大小。 表达式 a1a2 因此具有类型“int 的 5 元素数组”,它们可能不是赋值表达式的目标,也可能不是 ++ 的操作数或-- 运营商。当这些表达式出现在对foo 的调用中时,它们的类型将根据上述规则转换为“指向int 的指针”。因此foo 接收到a 的指针值,而不是数组值(这包含在将数组参数转换为指针类型的规则中)。所以foo中的表达式a的类型为int *,或者指向int的指针;因此,a 可能是赋值的目标,它可能是++-- 的操作数。

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

    【讨论】:

    • 我还是不知道在什么情况下,数组类型推导会得到实际的类型,能举个例子吗?
    【解决方案3】:
    main(int argc, char * argv[])
    

    main(int argc, char **argv)
    

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

    了解更多read this

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

     array = point; 
    array++;
    

    你已经提到它是错误的。

    【讨论】:

    • 数组衰减说明。顺便说一句,据说您提供的网址中的void by_reference(const T (&amp;array)[U]) 可以提供正确的 sizeof() 信息,但是当我在代码中对其进行测试时,出现错误。为什么?
    • 这是 C++ 中而不是 C 中的引用传递。记住引用只是同一个变量的别名。
    猜你喜欢
    • 2015-12-18
    • 1970-01-01
    • 2013-09-19
    • 2016-06-03
    • 1970-01-01
    • 2021-12-12
    • 2015-11-09
    • 2018-04-25
    • 1970-01-01
    相关资源
    最近更新 更多