C の宣言は式中心です。つまり、宣言の形式は、実行可能コードの式の形式と一致する必要があります。
たとえば、 という名前の整数へのポインタがあるとしますp
。が指す整数値にアクセスしたいので、次のようにポインタp
を逆参照します。
x = *p;
式 のタイプ*p
はint
; したがって、 の宣言はp
次の形式を取ります
int *p;
この宣言でint
は、 は型指定子、*p
は宣言子です。p
宣言子は、型指定子によって提供されない追加の型情報と共に、宣言されるオブジェクトの名前 ( ) を導入します。この場合、追加の型情報はp
ポインタ型です。p
宣言は、" is of type pointer to int
" または " p
is a pointer to type "として読み取ることができますint
。私は 2 番目の形式を使用することを好みますが、最初の形式を好む人もいます。
int *p;
その宣言をまたはのいずれかとして記述できるのは、C および C++ 構文の偶然ですint* p;
。どちらの場合も、次のように解析されます。int (*p);
つまり、*
は型指定子ではなく、常に変数名に関連付けられます。
へのポインターの配列があり、配列int
の i 番目の要素が指す値にアクセスしたいとします。次のように、配列に添字を付けて結果を逆参照します。
x = *ap[i]; // parsed as *(ap[i]), since subscript has higher precedence
// than dereference.
繰り返しますが、式の型はis *ap[i]
なのでint
、 の宣言はap
is
int *ap[N];
ここで、宣言子は、 へのポインターの配列である*ap[N]
ことを示します。 ap
int
ポイントを理解するために、ポインターへのポインターがint
あり、その値にアクセスしたいとします。繰り返しますが、ポインターを参照し、次にその結果を逆参照して整数値を取得します。
x = **pp; // *pp deferences pp, then **pp dereferences the result of *pp
式の型が であるため**pp
、int
宣言は
int **pp;
宣言子**pp
は、pp
が への別のポインターへのポインターであることを示しますint
。
通常、次のように、関数に渡すポインター値を変更する場合に、二重間接参照が多く発生します。
void openAndInit(FILE **p)
{
*p = fopen("AFile.txt", "r");
// do other stuff
}
int main(void)
{
FILE *f = NULL;
...
openAndInit(&f);
...
}
この場合、関数で の値を更新する必要がありf
ます。そのためには、へのポインターを渡す必要がありますf
。f
はすでにポインター型 ( ) であるためFILE *
、ポインターを a に渡していることを意味します。したがって、 as をFILE *
宣言します。inの式は inの式と同じオブジェクトを参照することに注意してください。 p
FILE **p
*p
openAndInit
f
main
宣言と式の両方[]
で、 との両方()
が unary よりも優先され*
ます。たとえば、次のように*ap[i]
解釈され*(ap[i])
ます。式ap[i]
はポインター型であり、*
そのポインターを逆参照します。したがって、ポインタap
の配列です。array へのポインタを宣言する場合は、次のように明示的に配列名でグループ化する必要があります。*
int (*pa)[N]; // pa is a pointer to an N-element array of int
また、配列内の値にアクセスする場合はpa
、添え字を適用する前に参照する必要があります。
x = (*pa)[i];
関数についても同様です。
int *f(); // f is a function that returns a pointer to int
...
x = *f(); // we must dereference the result of f() to get the int value
int (*f)(); // f is a pointer to a function that returns an int
...
x = (*f)(); // we must dereference f and execute the result to get the int value