【问题标题】:char argv[ ][ ] as main function argument, why not?char argv[ ][ ] 作为主函数参数,为什么不呢?
【发布时间】:2021-02-05 16:07:54
【问题描述】:

我从在线课程中了解到,char **argvchar *argv[ ] 都可以用作main 的参数。

我也知道它们实际上是相同的,它们都将 argv 声明为“指向 char 指针 (char *) 的指针 (*)”。

是什么使char argv[ ][ ] 作为main 的参数无效?

edit:实际上,char *argv[ ] 是在声明一个数组而不是一个指针吗?所以 argv 只衰减到一个指针而不是一个指针本身?

【问题讨论】:

  • 因为char argv[][] 不是一个有效的声明,无论你在哪里拥有它?而且系统正在传递一个jagged array,它只能在 C 中表示为指向指针的指针。
  • 是的,我同意,我在任何地方都没有看到char argv[][],但你能告诉我这是为什么吗?
  • 函数参数不能声明数组。
  • 它们是一样的。
  • @Someprogrammerdude: char (*argv)[] 是合法且可行的;允许使用指向未知大小数组的指针。 C 中没有规定指针必须指向完整类型。相比之下,char argv[][] 名义上声明了一个未知大小的数组数组,这违反了数组元素类型不得为不完整类型的约束(C 2018 6.7.6.2 1)。即使数组将被调整为指针,但约束可能在调整之前应用(可能有一些宽容度解释 C 标准对此的解释)。

标签: arrays c pointers arguments


【解决方案1】:

这个参数的声明

char argv[ ][ ]

无效,因为编译器需要知道数组的元素类型,在这种情况下是不完整类型char[]

此声明

char *argv[ ] 

声明元素类型为char *的不完整数组类型。

如果这样的声明被用作函数参数声明,那么它会被编译器隐式调整为指向该声明的元素类型的指针

char **argv

【讨论】:

  • 直截了当,解决了我所有的困惑,谢谢!
【解决方案2】:

有点杂草:

6.7.6.2 数组声明符
...
1    除了可选的类型限定符和关键字 static[] 可以分隔 表达式或*。如果它们分隔了一个表达式(它指定了一个数组的大小),则 表达式应具有整数类型。如果表达式是一个常量表达式,它应该 有一个大于零的值。 元素类型不能是不完整的或函数 输入。可选的类型限定符和关键字static 只能出现在 声明具有数组类型的函数参数,然后仅在最外层 数组类型推导。
...
4    如果不存在大小,则数组类型是不完整的类型。如果大小是* 而不是 作为表达式,数组类型是未指定大小的可变长度数组类型, 只能用于具有函数原型范围的声明或类型名称;143) 这样的数组仍然是完整的类型。如果大小是整数常量表达式 并且元素类型具有已知的常量大小,数组类型不是可变长度 数组类型;否则,数组类型是可变长度数组类型。 (可变长度 数组是实现不需要支持的条件特性;见 6.10.8.3。)
...
6.7.6.3 函数声明符(包括原型)
...
4    调整后,一个参数类型中的参数列表在一个函数声明器中,即 该函数定义的一部分不应有不完整的类型。
...
7    将参数声明为“类型的数组”应调整为“限定指针 type'',其中类型限定符(如果有)是在 [] 的 数组类型推导。如果关键字static也出现在[]的 数组类型推导,然后对函数的每次调用,对应的值 实际参数应提供对数组的第一个元素的访问,其中至少有 由 size 表达式指定的元素。
C 2011 Online Draft

所以,解压所有这些:

char argv[];

argv 声明为char 大小未知的数组。这个类型是不完整的,所以我们不能用类似

的东西来创建它的数组
char argv[][N];

并且通过扩展,我们无法创建该元素类型的未知大小的数组:

char argv[][];

“但是,”我听到你说,“char [] 类型的参数被调整为char * 类型,那么为什么char [][] 不等于char **?”

因为数组衰减不是这样工作的。让我们从一个泛型数组声明开始

T a[N];

a 的类型是“T 的 N 元素数组”,并且在大多数情况下(包括作为函数参数),其类型被转换(“衰减”)或“调整”为“指向T",这给了我们T *a;

现在让我们将类型T 替换为数组类型R [M]。用 T 替换它给我们

R a[N][M];

a的类型从“R的M元素数组的N个数组”调整为“R的M元素数组的指针”,这给了我们:

R (*a)[M];

不是

R **a;

所以char argv[][] 永远不会衰减到char **,它会衰减到char (*)[](这是一个不完整的类型,不允许作为函数参数)。但我们并没有走到那一步,因为char argv[][] 本身就是无效的。

【讨论】:

    【解决方案3】:

    如果您使用char argv[ ][ ],则认为每个单词都有相同数量的字母。每个 argv[i] 都指向另一个 char *,但是,这个全新的 char * 不需要都具有相同的大小。

    此外,如果您使用char argv[ ][ ] 运行代码,您的编译器可能会显示一个错误:“将'argv' 声明为多维数组必须对除第一个以外的所有维度都有边界”。实际上,int argc 参数包含传递的参数数量,即将分配多少个 char *。但是,没有任何关于 char * 每个 char * 先前分配的指向的大小的信息。

    【讨论】:

      猜你喜欢
      • 2020-02-06
      • 2011-08-14
      • 2022-07-14
      • 2015-09-06
      • 1970-01-01
      • 2018-08-12
      • 1970-01-01
      • 1970-01-01
      • 2015-11-07
      相关资源
      最近更新 更多