【问题标题】:What is the type of command-line argument `argv` in C?C 中命令行参数“argv”的类型是什么?
【发布时间】:2016-08-23 08:16:25
【问题描述】:

我正在阅读 C Primer Plus 中关于命令行参数 argv 的部分,但我很难理解这句话。

上面写着,

程序将命令行字符串存储在内存中,并存储 指针数组中每个字符串的地址。这个地址 数组存储在第二个参数中。按照惯例,这个指针指向 指针被称为argv,用于参数值。

这是否意味着命令行字符串作为指向char 数组的指针数组存储在内存中?

【问题讨论】:

  • Does this mean that the command line strings are stored in memory as an array of pointers to array of char? 是的。恕我直言,整个混乱是由 The program stores the command line strings in memory ... 引起的;关键是所有这些都发生在main() 被调用之前。 Main() 只是一个函数,它使用两个参数调用:一个 int 和一个指向字符串指针数组的指针。
  • @joop argv 不是“指向字符串指针数组的指针”,如果我们是迂腐的话。这整个问题实际上是关于“指向数组的指针”和“指向数组的第一个元素的指针”之间的区别。
  • 恕我直言,OP 的混淆是关于设置 args 的外部(“crt0”)和接收它的内部(main())。这也是(感知:腐烂)类型之间差异的原因。真的。
  • @joop 这是一个“语言律师”问题,这意味着它是关于标准 C 的,其中没有“crt0”并且参数的设置无关紧要,只要 @987654326 @ 行为与 C 标准中指定的一样
  • 后来添加了“language-lawyer”标签(由不了解问题的性质的人,恕我直言)我引用“crt0”是有原因的。真的。

标签: c arrays pointers language-lawyer argv


【解决方案1】:

argv 的类型为 char **它不是一个数组。它是指向char 的指针。命令行参数存储在内存中,每个内存位置的地址存储在一个数组中。该数组是指向char 的指针数组。 argv 指向此数组的第一个元素。

一些 大批 +-------+ +------+------+-------------+------+ argv ----------> | | | | | | | | 0x100 +------> | | | . . . . . . | |程序名称1 0x900 | | | | | | | | | +------+------+-------------+------+ +-------+ 0x100 0x101 | | +------+------+-------------+------+ | 0x205 | | | | | | 0x904 | +------> | | | . . . . . . | |精氨酸1 | | . | | | | | +-------+ +------+------+-------------+------+ | . | . 0x205 0x206 | . | | . | . | . | +--------+ 。 +------+------+-------------+------+ | | | | | | | | 0x501 +------> | | | . . . . . . | | argargc-1 | | | | | | | +-------+ +------+------+-------------+------+ | | 0x501 0x502 |空 | | | +-------+ 0xXXX代表内存地址

1。在大多数情况下,argv[0] 代表程序名称,但如果主机环境中没有程序名称,则 argv[0][0] 代表空字符。

【讨论】:

  • 整个字符串(&"string")的地址是否存储在数组中?
  • @SouravGhosh;好的。最终argv 指向char * 数组的第一个元素,这可能是标准在这种特殊情况下将其称为数组的原因。但是argv的类型是char **
  • 非常有用的 ASCII 模式!
  • 作为一个挑剔的,“一些数组”应该有一个存储空指针的元素。
  • 另外值得注意的是:argv[0] 不能保证保存程序名称(但在大多数情况下确实如此),但只能表示程序名称:@ 987654321@
【解决方案2】:

直接引用C11,第 §5.1.2.2.1/p2 章,程序启动,(强调我的)

int main(int argc, char *argv[]) { /* ... */ }

[...]如果argc的值大于零,数组成员argv[0]通过 argv[argc-1] inclusive 应包含指向字符串的指针,[...]

[...] 和argv 数组指向的字符串[...]

所以,基本上,argv 是一个指向字符串数组note 的第一个元素的指针。这可以从另一种形式

中更清楚地说明

int main(int argc, char **argv) { /* ... */ }

您可以将其改写为指向以空结尾的char 数组的第一个元素的指针数组的第一个元素的指针,但我更愿意坚持使用字符串。 p>


注意:

为了澄清上述答案中“指向数组第一个元素的指针”的用法,遵循§6.3.2.1/p3

除非它是sizeof 运算符、_Alignof 运算符或 一元 & 运算符,或者是用于初始化数组的字符串文字,具有 type ''array of type'' 被转换成一个类型为 ''pointer to type'' 的表达式,它指向 到数组对象的初始元素,并且不是左值。 [...]

【讨论】:

  • 那么整个string(&"string")的地址是存放在数组中的吗?或者是数组中存储的字符串的初始元素的地址?
  • @Jin 字符串起始元素的地址。
  • ...由于数组被传递给一个函数(main),它折叠成一个指针。所以argv 是一个指向数组的指针。试试sizeof argvargv++ 你会看到argv 是一个指针。
  • 那你为什么说“......作为指向空终止char数组的指针数组”,而不是“......作为指向空终止char的指针数组”?我认为这两个句子之间有区别..还是我错了?
  • @Sourac Ghosh 对不起,我的错!我认为“指向以 null 结尾的 char 数组的指针”是指指向整个字符串的指针(&“String”)
【解决方案3】:

这个帖子真是个火车残骸。情况如下:

  • 有一个包含argc+1 元素类型为char * 的数组。
  • argv 指向该数组的第一个元素。
  • 还有 argc 其他类型为 char 和各种长度的数组,其中包含表示命令行参数的以空字符结尾的字符串。
  • 指针数组的每个元素都指向char 数组之一的第一个字符;除了指针数组的最后一个元素,它是一个空指针。

有时人们会写“指向 X 数组的指针”来表示“指向 X 数组的第一个元素的指针”。您必须使用上下文和类型来确定它们是否确实意味着那个。

【讨论】:

  • 这个问题的某处必须完全重复。
【解决方案4】:

是的,没错。

argvchar**char*[],或者只是一个 char* 指针数组。

所以 argv[0] 是 char*(字符串),argv[0][0]char

【讨论】:

  • 如果它是一个以零结尾的字符串数组(char[],而不是char*),它只是char[]
  • @Rhymoid 非零终止字符,零终止字符串s
  • 你能举一个非零终止_string_s的例子吗?
  • @blue112 这样描述它令人困惑。还有存储"a list of\0strings like\0so\0" 的做法,它是一个以零结尾的字符串的(以零结尾的)数组。这不是 argv 的工作方式,但它使用(例如在Linux 内核的cmdline procfile 中)。 char* 不是字符串。
  • @hacks 它指向一个字符指针数组的第一个元素。
【解决方案5】:

argv 是一个指向字符的指针数组。

以下代码显示argv 的值、argv 的内容,并对argv 的内容指向的内存执行内存转储。希望这能阐明间接的含义。

#include <stdio.h>
#include <stdarg.h>

print_memory(char * print_me)
{
    char * p;
    for (p = print_me; *p != '\0'; ++p)
    {
        printf ("%p: %c\n", p, *p);
    }

    // Print the '\0' for good measure
    printf ("%p: %c\n", p, *p);

}

int main (int argc, char ** argv) {
    int i;

    // Print argv
    printf ("argv: %p\n", argv);
    printf ("\n");

    // Print the values of argv
    for (i = 0; i < argc; ++i)
    {
        printf ("argv[%d]: %p\n", i, argv[i]);
    }
    // Print the NULL for good measure
    printf ("argv[%d]: %p\n", i, argv[i]);
    printf ("\n");

    // Print the values of the memory pointed at by argv
    for (i = 0; i < argc; ++i)
    {
        print_memory(argv[i]);
    }

    return 0;
}

示例运行:

$ ./a.out Hello World!
argv: ffbfefd4

argv[0]: ffbff12c
argv[1]: ffbff134
argv[2]: ffbff13a
argv[3]: 0

ffbff12c: .
ffbff12d: /
ffbff12e: a
ffbff12f: .
ffbff130: o
ffbff131: u
ffbff132: t
ffbff133:
ffbff134: H
ffbff135: e
ffbff136: l
ffbff137: l
ffbff138: o
ffbff139:
ffbff13a: W
ffbff13b: o
ffbff13c: r
ffbff13d: l
ffbff13e: d
ffbff13f: !
ffbff140:

$

您有一个从ffbff12cffbff140 的大连续数组,其中包含命令行参数(标准不保证这是连续的,但通常是这样做的)。 argv 只包含指向该数组的指针,因此您知道在哪里查找单词。

argv 是一个指针……指向指针……指向字符

【讨论】:

  • 它不在 C 或 POSIX 标准中,但它可能被 System V ABI 标准保证是连续的。
  • software.intel.com/sites/default/files/article/402129/… 的第 34 页详细描述了该数组需要和不需要的内容:“参数字符串、环境字符串和辅助信息在信息块中没有特定顺序出现,它们不需要紧凑分配。” [但是“信息块”本身是内存顶部的一个定义明确的区域,被定义为包含所有字符串]。显然,这仅与本标准适用的系统有关。
【解决方案6】:

是的。

argv 的类型是char**,即指向char 的指针。基本上,如果您认为char* 是一个字符串,那么argv 就是一个指向字符串数组的指针。

【讨论】:

  • 字符串不必在数组中,但指向它们的指针是。此外,指针数组的末尾为空。
  • argv 的类型是char**,即指向 char 数组的指针数组的指针:不。没办法。
  • @hacks 需要详细说明吗?
  • char ** 被读取为指向char的指针,而不是指向char数组的指针数组的指针。这使得argv 的类型为char *((*)[])[]
  • @hacks 我的错。我希望让它更直观,但它完全不正确。
猜你喜欢
  • 2011-01-22
  • 1970-01-01
  • 1970-01-01
  • 2020-01-23
  • 2013-06-13
  • 2020-11-15
  • 2015-04-08
  • 2014-10-22
  • 1970-01-01
相关资源
最近更新 更多