私はちょうど C を学んでいて、メイン メソッドでこれらのどれを使用するべきか疑問に思っていました。違いはありますか?どちらがより一般的ですか?
10 に答える
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つではないことを明確にしています。それはポインタです。
警告の言葉
上記で述べたすべては、関数のパラメーターとして配列を取得した場合にのみ当てはまることに注意してください。ローカル配列を使用する場合、配列はポインターにはなりません。前に説明したように、配列はその値が読み取られるときにポインターに変換されるため、ポインターとして動作します。ただし、ポインタと混同しないでください。
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 プログラマーは、(適切な条件下で) どちらも交換可能であると考えるでしょう。経験豊富な英語話者が「they're」と「they are」を同じように簡単に読むように。
もっと重要なのは、それらを読んで、それらがどれほど似ているかを認識することです. 書くよりも多くのコードを読むことになり、両方に等しく慣れる必要があります。
違いはありませんが、 がchar *argv[]
可変長文字列 (通常はchar *
) の固定サイズの配列であることを示しているため、使用します。
C 配列とポインターは関数パラメーター リストで交換可能であるため、2 つの形式のいずれかを使用できます。http://en.wikipedia.org/wiki/C_(programming_language)#Array-pointer_interchangeabilityを参照してください。
実際には違いはありませんが、後者の方が読みやすいです。あなたが与えられるのは、2番目のバージョンが言うように、charポインタの配列です。ただし、最初のバージョンのように、暗黙的に double char ポインターに変換できます。
char ** → 文字ポインタへのポインタと char *argv [] は文字ポインタの配列を意味します。配列の代わりにポインターを使用できるため、両方を使用できます。
どちらのアプローチを使用しても特別なメリットはないと思います。コードの残りの部分と最も一致する規則を使用してください。
可変数または動的な数の文字列が必要な場合は、char** を使用する方が簡単です。ただし、文字列の数が固定されている場合は、char* var[] が優先されます。
これが時代遅れであることは承知していますが、C プログラミング言語を学んでいるだけで、それに関して大きなことを何もしていないのであれば、コマンド ライン オプションを使用しないでください。
コマンドライン引数を使用していない場合は、どちらも使用しないでください。メイン関数を次のように宣言するだけint main()
です
- プログラムのユーザーがファイルをプログラムにドラッグできるようにして、プログラムの結果を変更できるようにしたい、または
- コマンドラインオプションを処理したい(
-help
、 、またはターミナルまたはコマンドプロンプトで/?
後に続くその他のもの)program name
あなたにとってより意味のある方を使用してください。int main()
結局のところ、コマンドライン オプションを追加したくなった場合は、後で簡単に編集できます。