argv
的文章,我不太理解这个句子。它说:
程序将命令行字符串存储在内存中,并将每个字符串的地址存储在指针数组中。该数组的地址存储在第二个参数中。按照惯例,这个指向指针的指针被称为
argv
,表示参数值。这是否意味着命令行字符串以指向
char
数组的指针数组的形式存储在内存中?argv
的文章,我不太理解这个句子。argv
,表示参数值。char
数组的指针数组的形式存储在内存中?argv
是一个 char **
类型的指针。它不是一个数组。它是一个指向指向 char
的指针的指针。命令行参数存储在内存中,每个内存位置的地址存储在数组中。这个数组是一个指向 char
的指针数组。argv
指向这个数组的第一个元素。
一些 数组
+-------+ +------+------+-------------+------+ argv ----------> | | | | | | | | 0x100 +------> | | | . . . . . . | | 程序名称1 0x900 | | | | | | | | | +------+------+-------------+------+ +-------+ 0x100 0x101 | | +------+------+-------------+------+ | 0x205 | | | | | | Arg1 0x904 | +------> | | | . . . . . . | | | | . | | | | | +-------+ +------+------+-------------+------+ | . | . 0x205 0x206 | . | | . | . | . | +-------+ . +------+------+-------------+------+ | | | | | | | Argargc-1 | 0x501 +------> | | | . . . . . . | | | | | | | | | +-------+ +------+------+-------------+------+ | | 0x501 0x502 | NULL | | | +-------+
0xXXX 表示内存地址
1. 在大多数情况下,argv [0]
表示程序名称,但如果从主机环境中无法获取程序名称,则 argv [0] [0]
表示空字符。
argv
指向一个 char *
数组的第一个元素,这可能是标准将其在这种特定情况下称为数组的原因。但 argv
的类型是 char **
。 - haccks""
。 - SamBmain
),因此它会折叠成一个指针。所以argv
是一个指向数组的指针。尝试使用sizeof argv
和argv++
,你会发现argv
是一个指针。 - Klas Lindbäckargv
是指向数组的指针:不是的。argv
是一个指向指向char
的指针的指针。 - haccks这个主题太混乱了,以下是情况:
char *
的数组,它有argc+1
个元素。argv
指向该数组的第一个元素。argc
个其他类型为char
且长度各异的数组,包含表示命令行参数的空终止字符串。char
数组中的第一个字符;除了指针数组的最后一个元素是空指针。有时人们会写“指向X类型数组的指针”,意思是“指向X类型数组的第一个元素的指针”。你必须使用上下文和类型来确定他们是否实际上是这个意思。
是的,完全正确。
argv
是 char**
或者 char*[]
,或者说是 char* 指针的数组。
因此,argv[0]
是一个 char*
(字符串),而 argv[0][0]
则是一个 char
。
"a list of\0strings like\0so\0"
,它是一个以零结尾的字符串数组。这 不 是 argv
的工作方式,但它 被用于 (例如在 Linux 内核的 cmdline
procfile 中)。char*
不是一个字符串。 - user824425argv
本身的含义。 - user824425argv
的类型是 char**
,即指向 char
指针的指针。基本上,如果将 char*
视为字符串,则 argv
是指向字符串数组的指针。argv
的类型是 char**
,即指向字符数组指针的数组的指针。不行,绝对不行。 - hacckschar **
读作 指向字符指针的指针,而不是 指向指针数组的数组指针。这使得 argv
的类型为 char *((*)[])[]
。 - haccks严格来说,argv
必须具备一些属性才能成为数组。让我们考虑其中的一些:
¹/ 不能有一个由空指针指向的数组,因为空指针保证是与任何对象的地址不同。因此,在下面的代码中,argv
不能是一个数组:
#include <assert.h>
int main(int argc, char *argv[]) {
if (argv) return main(0, 0);
assert(argv == 0); // argv is a null pointer, not to be dereferenced
}
²/ 给数组赋值是无效的。例如,char *argv[] = { 0 }; argv++;
是一个约束违规,但是 int main(int argc, char *argv[]) { argv++; }
可以编译并运行良好。因此,我们必须从这一点得出结论,即在声明为参数时,argv
不是一个数组,而是一个(可能)指向数组的指针。(这实际上与第1点相同,但从不同的角度来看,因为使用空指针作为 argv
调用 main
实际上是重新分配了 argv
,这是我们不能对数组做的事情)。
³/ ... 正如 C 标准所说:
sizeof 运算符的另一个用途是计算数组中元素的数量:sizeof array / sizeof array[0]
例如:
#include <assert.h>
int main(int argc, char *argv[]) {
size_t size = argc+1; // including the NULL
char *control[size];
assert(sizeof control / sizeof *control == size); // this test passes, because control is actually an array
assert(sizeof argv / sizeof *argv == size); // this test fails for all values of size != 1, indicating that argv isn't an array
}
⁴/ 一元的 &
取地址运算符被定义为,当应用于数组时,将产生不同类型的相同值,例如:
#include <assert.h>
int main(int argc, char *argv[]) {
char *control[42];
assert((void *) control == (void *) &control); // this test passes, because control is actually an array
assert((void *) argv == (void *) &argv); // this test fails, indicating that argv isn't an array
}
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:
$
ffbff12c
到 ffbff140
这么大的连续数组,其中包含命令行参数(这不是标准保证的连续性,但通常是这样做的)。argv
只包含指向该数组的指针,因此您知道在哪里查找单词。
argv
是一个指向指针的指针,指向字符。
argv
按照C标准规定的方式运行即可。 - M.Margv
数组在进程启动时以适合传递给main
的引用格式存储在内存中。因此,crt0
libc启动代码除了将指针传递给main()
之外,不必对argv做任何处理。在Linux中,内核将argv和环境块放置在用户空间堆栈的顶部。System V ABI的x86版本在线上可以查看。 - Peter Cordes