コマンドライン引数argv
に関するCプライマープラスのセクションを読んでいますが、この文章を理解することが困難です。
それは言う、
プログラムはコマンドライン文字列をメモリに格納し、各文字列のアドレスをポインタの配列に格納します。この配列のアドレスは、2番目の引数に格納されます。慣例により、このポインタへのポインタは、引数値に対して
argv
と呼ばれます。
これは、コマンドライン文字列がchar
の配列へのポインタの配列としてメモリに格納されることを意味しますか?
_C11
_からの直接引用、§5.1.2.2.1/ p2章、プログラムの起動、(鉱山を強調)
int main(int argc, char *argv[]) { /* ... */ }
[...]
argc
の値がゼロより大きい場合、配列メンバー_argv[0]
_から_argv[argc-1]
_までは、文字列へのポインターを含む、[です。 ..]
そして
[...]と
argv
配列が指す文字列[...]
したがって、基本的に、argv
は文字列の配列の最初の要素へのポインタです 注意。これは代替形式からより明確にすることができます。
int main(int argc, char **argv) { /* ... */ }
これを、nullで終了するchar
配列の最初の要素へのポインターの配列の最初の要素へのポインターとして言い換えることができますが、私は文字列にこだわりたいと思います
注意:
上記の回答で「配列の最初の要素へのポインタ」の使用を明確にするために、§6.3.2.1/ p3に従います。
sizeof
演算子、__Alignof
_演算子、または単項_&
_演算子のオペランドである場合、または配列の初期化に使用される文字列リテラルである場合を除いて、anタイプ ''タイプの配列 ''を持つ式は、タイプ ''タイプへのポインター ''という式に変換されます配列オブジェクトの初期要素を指しますであり、左辺値ではありません。 [...]
argv
はタイプchar **
。 配列ではありません。 char
へのポインターへのポインターです。コマンドライン引数はメモリに格納され、各メモリ位置のアドレスは配列に格納されます。この配列は、char
へのポインターの配列です。 argv
は、この配列の最初の要素を指します。
いくつか 配列 + ------- + + ------ + ------ + ---- --------- + ------ + argv ----------> | | | | | | | | 0x100 + ------> | | | 。 。 。 。 。 。 | |プログラム名1 0x900 | | | | | | | | | + ------ + ------ + ------------- + ------ + + ------- + 0x100 0x101 | | + ------ + ------ + ------------- + ------ + | 0x205 | | | | | | 0x904 | + ------> | | | 。 。 。 。 。 。 | |引数1 | | 。 | | | | | + ------- + + ------ + ------ + ------------- + ------ + | 。 | 。 0x205 0x206 | 。 | | 。 | 。 | 。 | + ------- +。 + ------ + ------ + ------------- + ------ + | | | | | | | | 0x501 + ------> | | | 。 。 。 。 。 。 | |引数argc-1 | | | | | | | + ------- + + ------ + ------ + ------------- + ------ + | | 0x501 0x502 | NULL | | | + ------- + 0xXXXはメモリアドレスを表します
1.ほとんどの場合argv[0]
はプログラム名を表しますが、プログラム名がホスト環境から利用できない場合はargv[0][0]
はヌル文字を表します。
このスレッドは、このような列車事故です。ここに状況があります:
argc+1
のchar *
要素を持つ配列があります。argv
は、その配列の最初の要素を指します。argc
char
型の他、さまざまな長さの配列があり、コマンドライン引数を表すnullで終了する文字列が含まれています。char
の配列の1つの最初の文字を指します。ポインタの配列の最後の要素を除いて、これはnullポインタです。「Xの配列へのポインタ」を「Xの配列の最初の要素へのポインタ」を意味するように書く人もいます。コンテキストとタイプを使用して、実際に意味があるかどうかを判断する必要があります。
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
はchar**
またはchar*[]
、または単にchar *ポインタの配列。
したがって、argv [0]はchar*
(文字列)およびargv[0][0]
はchar
です。
はい。
argv
のタイプはchar**
、つまりchar
へのポインターへのポインター。基本的に、char*
を文字列にすると、argv
は文字列の配列へのポインタになります。