C言語ポインタを徹底的に攻略する

3757 ワード

前述したように、ポインタ配列、2次元配列ポインタ、関数ポインタなど、いくつかの複雑なポインタについて説明しました.定義形式は次のとおりです.
  • int *p1[6];//ポインタ配列
  • int *(p2[6]);//ポインタ配列、上の形式と等価
  • int (*p3)[6];//2 D配列ポインタ
  • int (*p4)(int, int);//関数ポインタ
  • 私は大部分の初心者が上のいくつかの形式のポインタに対してすべてとても迷って、どこから理解するべきか分からないと信じて、どうしてp 1、p 2は配列で、p 3はポインタで、それらはただ1つの括弧の違いです.ポインタはC言語の中で最も強大で最も柔軟な一部であり、最も理解しにくい一部でもあり、それはC言語を学ぶ重点であり、ポインタを学ばなければC言語を学ぶことができない.もし皆さんが上記のいくつかの形式のポインタが無理に受け入れられると思ったら、次の2つのポインタは人を狂わせるのではないでしょうか.
  • char *(* c[10])(int **p);
  • int (*(*(*pfunc)(int *))[5])(int *);

  • コツさえ見つければ、どんなに複雑な針でも理解できるので、この節ではこの窓紙を突き破りましょう.C言語標準では、1つの記号の定義に対して、コンパイラは常にその名前から読み出し、優先順位順に順次解析することを規定している.はい、名前から始まり、冒頭からでも末尾からでもありません.これは複雑なポインタを理解する鍵です.初心者の場合、いくつかの演算子の優先度は非常に混同されやすく、優先度が高い順に次のようになります.
  • 定義の括弧( )で囲まれた部分.
  • 接尾辞オペレータ:カッコ( )は関数であり、角カッコ[ ]は配列であることを示します.
  • プレフィックスオペレータ:アスタリスク*は、「xxxへのポインタ」を表します.

  • 「絶殺技」を学び、次に浅いから深く、上のポインタ定義を一つ一つ打ち破る.
    1) int *p1[6];
    p 1から理解すると、左側は*、右側は[],[]の優先度が*より高いため、コンパイラはまずp1[6]を解析し、p 1はまず6つの要素を持つ配列であり、それからint *を解析し、配列要素のタイプを説明するために使用される.全体的にp 1は6つのint*要素を持つ配列,すなわちポインタ配列である.
    2) int (*p3)[6];
    p 3から理解すると、()の優先度が最も高く、コンパイラはまず(*p3)を解析し、p 3はまずポインタであり、残りのint [6]はp 3が指すデータのタイプであり、6つの要素を持つ1次元配列である.全体的に、p 3は6つのint要素配列を有するポインタ、すなわち2次元配列ポインタを指す.
    ポインタで配列要素を遍歴できるようにするには、3 D配列ポインタが実際に指すデータ型が2 D配列であり、2 D配列ポインタが実際に指すデータ型が1 D配列であり、1 D配列ポインタが実際に指すデータ型が1 D配列であり、1 D配列ポインタが実際に指す基本型である.式では、配列名も同様に変換されます(次元が下がります).
    3) int (*p4)(int, int);
    p 4から理解すると、()の優先度が最も高く、コンパイラはまず(*p4)を解析し、p 4はまずポインタであり、その後の()はp 4が関数を指し、括弧の中のint, intがパラメータリストであり、冒頭のintは関数の戻り値タイプを説明するために使用される.全体的に,p 4はint func(int, int);のプロトタイプの関数を指すポインタである.
    4) char *(* c[10])(int **p);
    この定義にはcとpの2つの名前があり、一見pはポインタ変数の名前ですが、残念ながらこれは間違っています.pがポインタ変数名であれば、c[10]という書き方で新しい名前が定義されているのは不思議です.cを変数とする名前は、まず括弧の内部(緑の太字):
    char * (* c[10]) (int **p);
    []の優先度は*より高く、コンパイラはc[10]を解析し、cはまず配列であり、その前の*は各配列要素がポインタであることを示しているが、どのようなタイプのデータを指すかはまだ分からない.全体的に、(* c[10])は、cがポインタ配列であることを示しているが、ポインタが指すデータ型はまだ確定していない.かっこを選択します.優先度ルール(()の優先度が*)より高い場合は、右側(赤の太字)を見てください.
    char * (* c[10]) (int **p); ( )は関数であり、int **pは関数パラメータである.左(オレンジ色の太字):
    char * (* c[10]) (int **p); char *は、関数の戻り値のタイプです.全体的に定義を2つの部分に分けることができます.
    char * (* c[10]) (int **p);
    緑色の太字はcがポインタ配列であることを示し、赤色の太字はポインタが指すデータ型を示し、合わせてcは10要素を持つポインタ配列であり、各ポインタはchar *func(int **p);の原型を持つ関数を指す.
    5) int (*(*(*pfunc)(int *))[5])(int *);
    pfuncから理解するには、括弧の内部(緑の太字):
    int (*(*(*pfunc)(int *))[5])(int *);
    pfuncはポインタです.かっこを飛び出して、両側(赤い太字):
    int (*(*(*pfunc)(int *))[5])(int *);
    優先度ルールに従って右側の(int *)を先に見るべきで、これは関数であり、int *はパラメータリストであることを示します.さらに左側の*を見ると、関数の戻り値はポインタであり、ポインタが指すデータ型はまだ確定していないことを示しています.上の2つの部分を全体に合成します.下の青い太字に示すように、pfuncは関数を指すポインタであることを示しています.現在、関数のパラメータリストが決定され、戻り値がポインタであることも知っています(ただし、どのタイプのデータを指すか分かりません).
    int (* (*(*pfunc)(int *)) [5])(int *);
    青い太字以外の部分は、関数がどのタイプのポインタを返すかを説明するために使用されます.次に、カッコ(赤い太字)を外側にジャンプします.
    int (* (*(*pfunc)(int *)) [5])(int *);
    []の優先度は*より高く、まず右を見て、[5]はこれが配列であることを示し、さらに左を見て、*は配列の各要素がポインタであることを示している.すなわち,*[5]はポインタ配列であり,関数が返すポインタはこのような配列を指す.では、ポインタ配列のポインタはどのようなタイプのデータを指しているのでしょうか.さらにかっこ(オレンジ色の太字):
    int (* (*(*pfunc)(int *)) [5]) (int *);
    オレンジ色の部分の右を見てください.関数です.左を見てください.関数の戻り値のタイプです.すなわち,ポインタ配列中のポインタは,プロトタイプint func(int *);の関数を指す.上の3つの部分を合わせると、pfuncは関数ポインタ(青い部分)であり、この関数の戻り値はポインタ配列(赤い部分)を指し、ポインタ配列のポインタはint func(int *);の関数(オレンジ色の部分)を指します.
    転載先:https://www.cnblogs.com/ZYDZ/p/9496080.html