私はCを学習しているだけで、メインメソッドでこれらのどれを使用する必要があるのかと思っていました。違いはありますか?どちらがより一般的ですか?
char **argv
はchar *argv[]
、パラメーター宣言とまったく同じです(パラメーター宣言としてのみ)。2.配列はポインタではありません。
私はCを学習しているだけで、メインメソッドでこれらのどれを使用する必要があるのかと思っていました。違いはありますか?どちらがより一般的ですか?
char **argv
はchar *argv[]
、パラメーター宣言とまったく同じです(パラメーター宣言としてのみ)。2.配列はポインタではありません。
回答:
Cを学習しているだけなので、一般的なことではなく、配列とポインタの違いを最初に理解することをお勧めします。
パラメータと配列の領域では、先に進む前に明確にしておくべきいくつかの混乱するルールがあります。まず、パラメーターリストで宣言したものは特別に扱われます。Cの関数パラメーターとしては意味がないような状況があります。これらは
2番目は多分すぐに明確ではありません。しかし、配列の次元のサイズがCの型の一部である(そして、次元のサイズが指定されていない配列の型が不完全である)と考えると、明らかになります。したがって、配列を値渡し(コピーを受け取る)する関数を作成する場合、1つのサイズでしか実行できません。さらに、配列は大きくなる可能性があり、Cはできるだけ高速にしようとします。
Cでは、これらの理由により、配列値は存在しません。配列の値を取得する場合、代わりに取得するのはその配列の最初の要素へのポインターです。そして、ここに実際にすでに解決策があります。無効な配列パラメーターを事前に描画する代わりに、Cコンパイラーはそれぞれのパラメーターの型をポインターに変換します。これを覚えておいてください、それは非常に重要です。パラメータは配列ではなく、それぞれの要素タイプへのポインタになります。
ここで、配列を渡そうとすると、代わりに渡されるのは配列の最初の要素へのポインターです。
完了のために、そしてこれは問題をよりよく理解するのに役立つと思いますので、関数をパラメーターとして使用しようとするときの状況を見てみましょう。確かに、最初は意味がありません。パラメータはどのように関数にすることができますか?ええと、もちろんその場所に変数が必要です!そのため、コンパイラーがこれを行うときに行うことは、やはり、関数を関数ポインターに変換することです。関数を渡そうとすると、代わりにそれぞれの関数へのポインタが渡されます。したがって、以下は同じです(配列の例と同様)。
void f(void g(void));
void f(void (*g)(void));
括弧*g
が必要であることに注意してください。それ以外の場合は、関数void*
returnへのポインタの代わりに、関数returnを指定します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つではないことが明らかになります。ポインタです。
関数のパラメータとして配列を取得した場合にのみ、上記で述べたすべてが当てはまることに注意してください。ローカル配列を操作する場合、配列はポインターにはなりません。これは、あろう挙動先に説明したように、その値が読み込まれたときアレイはポインタに変換されるので、ポインタとして。ただし、ポインタと混同しないでください。
典型的な例の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;
どちらでも使用できます。それらは完全に同等です。litbのコメントと彼の回答を参照してください。
それは本当にそれをどのように使いたいかに依存します(そしてあなたはどちらの場合でも使うことができます):
// echo-with-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char **argv)
{
while (--argc > 0)
{
printf("%s ", *++argv);
}
printf("\n");
return 0;
}
// echo-without-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for (i=1; i<argc; i++)
{
printf("%s ", argv[i]);
}
printf("\n");
return 0;
}
どちらがより一般的であるか-それは問題ではありません。コードを読んでいる経験豊富なCプログラマーは、どちらも(適切な条件下で)交換可能と見なします。経験豊富な英語を話す人が「彼らは」と「彼らは」を同じくらい簡単に読むのと同じように。
さらに重要なことは、それらを読むことを学び、それらがどれほど類似しているかを認識することです。あなたはあなたが書くよりも多くのコードを読むでしょう、そしてあなたは両方に等しく慣れる必要があるでしょう。
char**
は、実際の配列として扱うべきではないことを思い出させるので、sizeof[arr] / sizeof[*arr]
ます。
Cの配列と同様に、2つの形式のいずれかを使用できます。関数パラメーターリストではポインターを交換できます。http://en.wikipedia.org/wiki/C_(programming_language)#Array-pointer_interchangeabilityを参照してください。
私はこれが古いことを知っていますが、Cプログラミング言語を習得していて、それで主要なことを何もしていない場合は、コマンドラインオプションを使用しないでください。
コマンドライン引数を使用していない場合は、どちらも使用しないでください。メイン関数をint main()
次のように宣言するだけです
-help
、/?
または後に行く他の事program name
の端末またはコマンドプロンプトで)あなたにとってより意味のある方を使用してください。それ以外の場合は、int main()
結局のところ、コマンドラインオプションを追加したい場合は、後で簡単に編集できます。