char** argv と char* argv[] のどちらを使用すればよいですか? 質問する

char** argv と char* argv[] のどちらを使用すればよいですか? 質問する

私は C を勉強しているところですが、メイン メソッドでどちらを使用すればよいのか疑問に思っています。何か違いはありますか? どちらがより一般的ですか?

ベストアンサー1

Cを勉強している今、違い配列とポインタを最初に比較するのではなく、一般もの。

パラメータと配列の領域では、先に進む前に明確にしておくべきいくつかの紛らわしいルールがあります。まず、パラメータ リストで宣言したものは特別に扱われます。C言語の関数パラメータとして意味をなさない状況があります。

  • パラメータとしての関数
  • パラメータとしての配列

パラメータとしての配列

2 番目の「多分」はすぐには分かりません。しかし、配列の次元のサイズが C の型の一部であることを考慮すると明らかになります (次元のサイズが指定されていない配列は不完全な型です)。したがって、配列を値渡し (コピーを受け取る) する関数を作成する場合、1 つのサイズに対してのみ実行できます。さらに、配列は大きくなる可能性があり、C は可能な限り高速化しようとします。

Cでは、これらの理由から、配列値配列の値を取得したい場合、代わりに取得するのはその配列の最初の要素へのポインタです。そして、実はここにすでに解決策があります。Cコンパイラは、配列パラメータを無効として事前に描画する代わりに、変身それぞれのパラメータの型はポインタになります。これは非常に重要なので覚えておいてください。パラメータは配列ではなく、それぞれの要素型へのポインタになります。

ここで、配列を渡そうとすると、代わりに配列の最初の要素へのポインターが渡されます。

エクスカーション: パラメータとしての関数

補足として、また、この方が理解を深めるのに役立つと思うので、関数をパラメータとして持とうとするとどうなるかを見てみましょう。確かに、最初は意味がわかりません。パラメータが関数になるなんてあり得ますか?ああ、もちろん、その場所には変数が必要です!それで、コンパイラがそれが起こると、再び、変身関数を関数ポインタ関数を渡そうとすると、代わりにそれぞれの関数へのポインタが渡されます。したがって、以下は同じです (配列の例と同様)。

void f(void g(void));
void f(void (*g)(void));

を括弧で囲む*g必要があることに注意してください。括弧がなければ、void*を返す関数へのポインターではなく、 を返す関数が指定されることになりますvoid

配列に戻る

さて、最初に、配列は不完全な型になる可能性があると述べました。これは、サイズをまだ指定していない場合に発生します。配列パラメータは存在せず、代わりに配列パラメータはすべてポインタであることがすでにわかっているので、配列のサイズは関係ありません。つまり、コンパイラは次のすべてを変換しますが、すべて同じものです。

int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);

もちろん、任意のサイズを入れることはあまり意味がないので、単に捨てられます。そのため、C99 ではこれらの数字に新しい意味を持たせ、括弧内に他のものを入れることができるようになりました。

// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory. 
int main(int c, char *argv[static 5]);

// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);

// says the same as the previous one
int main(int c, char ** const argv);

最後の 2 行は、関数内で「argv」を変更できないことを示しています。これは const ポインタになっています。ただし、これらの C99 機能をサポートする C コンパイラはごくわずかです。ただし、これらの機能により、「配列」が実際には配列ではないことが明確になります。これはポインタです。

警告の言葉

上で述べたことは、配列を次のように取得した場合にのみ当てはまります。パラメータ関数の。ローカル配列を扱う場合、配列はポインタではありません。振る舞う前述のように、配列は値が読み取られるときにポインタに変換されるため、ポインタとして使用しないでください。ただし、ポインタと混同しないでください。

典型的な例の 1 つは次のとおりです。

char c[10]; 
char **c = &c; // does not work.

typedef char array[10];
array *pc = &c; // *does* work.

// same without typedef. Parens needed, because [...] has 
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;

おすすめ記事