コード1
#include<stdio.h>
int main(int argc, char *argv[])
{
int j;
printf("%d", argv[1][0]);
return 0;
}
コード2
#include<stdio.h>
int main(int argc, char **argv)
{
int j;
printf("%d", argv[1][0]);
return 0;
}
CODE 1およびCODE 2は両方とも同じ出力を提供します。ただし、CODE 1とCODE 2のメイン関数のargument 2は異なります。ポインターの配列は、コンパイル時にデータセクションの上に作成されます。 argvはポインターの配列です。次に、メイン関数で引数を文字へのポインターへのポインターとして宣言する必要があります。つまり、** argv。コード1のように宣言するのはどうですか?
Cの基本はchar** x
およびchar* x[]
は、同じことを表す2つの方法です。両方とも、パラメーターがポインターの配列へのポインターを受け取ることを宣言します。いつでも書くことができることを思い出してください:
char *parray[100];
char **x;
x = &parray[0];
そして、xを同じように使用します。
基本的に、char * argv []はcharポインターの配列を意味し、char ** argvはcharポインターへのポインターを意味します。
どの配列でも、配列の名前は配列の最初の要素へのポインターです。つまり、最初の要素のアドレスが含まれています。
したがって、以下のコードでは、char配列xで、xは文字である最初の要素「1」へのポインターです。したがって、それは文字へのポインタです。
また、配列arrでは、arrはポインターの最初の要素xであり、それ自体が文字へのポインターです。したがって、別のポインターへのポインターです。
したがって、xはchar *、arrはchar **です。
関数で何かを受け取る際の基本的なルールは、受け取るもののタイプを伝える必要があるということです。したがって、char **を受け取りたいと単純に言うか、char * arr []と言うこともできます。
最初のケースでは、複雑なことを考える必要はありません。単純に、char *の配列を受け取っていることを知っています。これを知らないの?それで、私たちはそれを受け取り、それを使用します。
2番目のケースでは、arrはchar **であると上で説明したように簡単です。これをタイプとして入れて安全に受け取ることができます。これでシステムは受け取ったもののタイプを認識し、配列注釈を使用するだけで次の要素にアクセスできます。配列の開始アドレスを受け取ったので、必ず次の要素に進むことができ、型がわかると、それに含まれるものとそれをさらに使用する方法がわかります。 charへのポインタが含まれていることがわかっているので、それらにも合法的にアクセスできます。
void func1(char* arr[])
{
//function body
}
void func2(char** arr)
{
//function body
}
int main()
{
//x, y and z are pointer to char
char x[3]={'1', '2', '3'};
char y[3]={'4', '5', '6'};
char z[3]={'7', '8', '9'};
//arr is pointer to char pointer
char* arr[3]={x, y, z};
func1(arr);
func2(arr);
}
それらはまったく同じです。 C11標準状態の§5.1.2.2.2:
プログラムの起動時に呼び出される関数の名前は
main
です。実装は、この関数のプロトタイプを宣言しません。int
の戻り値の型で、パラメータなしで定義されます:int main(void) { /* ... */ }
または2つのパラメーター(ここでは
argc
およびargv
と呼びますが、宣言されている関数に対してローカルであるため、任意の名前を使用できます):int main(int argc, char *argv[]) { /* ... */ }
または同等;10) または他の実装定義の方法で。
10)したがって、
int
はint
として定義されたtypedef名に置き換えることができます。また、argv
のタイプはchar ** argv
として記述できます。
明らかに、両方の宣言が同一であることを意図しています。その上、規則は§6.7.6.3/ 7で説明されています:
''type ''の配列としてのパラメーターの宣言は、 ''type ''への修飾ポインターに調整されます。型修飾子(ある場合)は、配列型の派生の
[
および]
内で指定されます。 ...
このような配列を宣言する
char array[]
constになります。つまり、次のコードを取得できません。
char array[] = "hello";
array = "hey";
2番目の文字列が小さく、このエラーが収まるはずです
エラー:配列型 'char [6]'は割り当てられません
あなたが持っている場合 **argv
あなたは書ける
main(int argc, char **argv)
{
char **other_array;
/*
* do stuff with other_array
*/
argv = other_array;
}
あなたが持っている場合 *argv[]
その後
main(int argc, char *argv[])
{
char **other_array;
/*
* do stuff with other_array
*/
argv = other_array;
}
あなたにこの警告を与えます
警告:「char **」から「const char **」に割り当てると、ネストされたポインター型の修飾子が破棄されます
したがって、技術的にはconst
を記述したかのように小さな最適化です