1. ホーム
  2. c

[解決済み] char** argvとchar* argv[]のどちらを使うべきですか?

2022-08-07 09:51:06

質問

C言語を勉強しているのですが、mainメソッドにこのうちのどれを使ったらいいのか悩んでいます。何か違いがあるのでしょうか?どちらがより一般的ですか?

どのように解決するのですか?

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コンパイラはごくわずかです。しかし、これらの機能によって、"array"は実際には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;