ポインタ宣言
ポインタは、他の型の関数またはオブジェクトを参照するオブジェクトの一種であり、修飾子を追加する場合があります。ポインタは、特別なヌルポインタ値で示される何も参照しないこともあります。
目次 |
[編集] 構文
ポインタ宣言の宣言構文では、型指定子シーケンスは参照される型(関数型またはオブジェクト型であり、不完全型である場合もある)を指定し、宣言子は次の形式をとります。
* attr-spec-seq (オプション) qualifiers (オプション) declarator |
|||||||||
ここでdeclaratorは、宣言されるポインタの名前を付ける識別子、または別のポインタ宣言子(ポインタへのポインタを示す)である場合があります。
float *p, **pp; // p is a pointer to float // pp is a pointer to a pointer to float int (*fp)(int); // fp is a pointer to function with type int(int)
* と識別子(または他のネストされた宣言子)の間に現れるqualifiersは、宣言されるポインタの型を修飾します。
int n; const int * pc = &n; // pc is a non-const pointer to a const int // *pc = 2; // Error: n cannot be changed through pc without a cast pc = NULL; // OK: pc itself can be changed int * const cp = &n; // cp is a const pointer to a non-const int *cp = 2; // OK to change n through cp // cp = NULL; // Error: cp itself cannot be changed int * const * pcp = &cp; // non-const pointer to const pointer to non-const int
attr-spec-seq(C23)は、宣言されたポインタに適用される属性のオプションのリストです。
[編集] 説明
ポインタは間接参照に使用され、これは遍在するプログラミングテクニックです。参照渡しセマンティクスを実装するため、動的記憶域期間を持つオブジェクトにアクセスするため、「オプション」型(ヌルポインタ値を使用)を実装するため、構造体間の集約関係、コールバック(関数ポインタを使用)、汎用インターフェース(voidへのポインタを使用)、その他多くの用途に使用できます。
[編集] オブジェクトへのポインタ
オブジェクトへのポインタは、オブジェクト型(不完全型である場合もある)の式に適用されるアドレス演算子の結果で初期化できます。
int n; int *np = &n; // pointer to int int *const *npp = &np; // non-const pointer to const pointer to non-const int int a[2]; int (*ap)[2] = &a; // pointer to array of int struct S { int n; } s = {1} int* sp = &s.n; // pointer to the int that is a member of s
ポインタは、間接参照演算子(単項*)のオペランドとして現れることがあり、これは参照されるオブジェクトを識別する左辺値を返します。
int n; int* p = &n; // pointer p is pointing to n *p = 7; // stores 7 in n printf("%d\n", *p); // lvalue-to-rvalue conversion reads the value from n
struct および union 型のオブジェクトへのポインタは、ポインタによるメンバアクセス演算子 -> の左辺オペランドとして現れることもあります。
配列からポインタへの暗黙の変換により、配列の最初の要素へのポインタは配列型の式で初期化できます。
int a[2]; int *p = a; // pointer to a[0] int b[3][3]; int (*row)[3] = b; // pointer to b[0]
配列の要素へのポインタに対しては、特定の加算、減算、複合代入、インクリメント、デクリメント演算子が定義されています。
オブジェクトへのポインタに対しては、状況によっては比較演算子が定義されています。同じアドレスを表す2つのポインタは等しく比較され、2つのヌルポインタ値は等しく比較され、同じ配列の要素へのポインタはそれらの要素の配列インデックスと同じように比較され、構造体メンバへのポインタはそれらのメンバの宣言順序で比較されます。
多くの実装では、ランダムな起源のポインタの厳密な全順序も提供しています。例えば、それらが連続した(「フラットな」)仮想アドレス空間内のアドレスとして実装されている場合などです。
[編集] 関数へのポインタ
関数へのポインタは、関数のアドレスで初期化できます。関数からポインタへの変換により、アドレス演算子はオプションです。
void f(int); void (*pf1)(int) = &f; void (*pf2)(int) = f; // same as &f
関数とは異なり、関数へのポインタはオブジェクトであり、配列に格納したり、コピーしたり、代入したり、他の関数への引数として渡したりできます。
関数へのポインタは、関数呼び出し演算子の左辺オペランドとして使用でき、これにより参照先の関数が呼び出されます。
#include <stdio.h> int f(int n) { printf("%d\n", n); return n * n; } int main(void) { int (*p)(int) = f; int x = p(7); }
関数ポインタを間接参照すると、参照先の関数に対する関数指定子が得られます。
int f(); int (*p)() = f; // pointer p is pointing to f (*p)(); // function f invoked through the function designator p(); // function f invoked directly through the pointer
(同じ関数を参照している場合) 等価比較演算子は関数へのポインタに対して定義されています。
関数のパラメータのトップレベルの修飾子を無視する互換性のある型のため、パラメータのみがトップレベルの修飾子で異なる関数へのポインタは相互に交換可能です。
int f(int), fc(const int); int (*pc)(const int) = f; // OK int (*p)(int) = fc; // OK pc = p; // OK
[編集] voidへのポインタ
任意の型のオブジェクトへのポインタは、暗黙的に変換して、voidへのポインタ(オプションでconstまたはvolatile修飾されている場合がある)に変換でき、その逆も可能です。
int n=1, *p=&n; void* pv = p; // int* to void* int* p2 = pv; // void* to int* printf("%d\n", *p2); // prints 1
voidへのポインタは、未知の型のオブジェクトを渡すために使用されます。これは、汎用インターフェースで一般的です。mallocはvoid*を返します。qsortは、2つのconst void*引数を受け取るユーザー提供のコールバックを期待します。pthread_createは、void*を受け入れて返すユーザー提供のコールバックを期待します。すべての場合において、使用前にポインタを正しい型に変換する責任は呼び出し側にあります。
[編集] ヌルポインタ
すべての型のポインタには、その型の*ヌルポインタ値*として知られる特別な値があります。値がヌルであるポインタは、オブジェクトまたは関数を参照しません(ヌルポインタの間接参照は未定義の動作です)。また、値が*ヌル*である同じ型のすべてのポインタと等しく比較されます。
ポインタをヌルに初期化したり、既存のポインタにヌル値を代入したりするには、ヌルポインタ定数(NULL、または値ゼロの任意の整数定数)を使用できます。静的初期化もポインタをヌル値に初期化します。
ヌルポインタは、オブジェクトの不在を示すために使用されるか、または他の種類の誤り条件を示すために使用できます。一般に、ポインタ引数を受け取る関数は、その値がヌルであるかどうかをチェックし、そのケースを異なる方法で処理する必要がほとんど常にあります(たとえば、freeはヌルポインタが渡されたときに何もしません)。
[編集] 注記
任意のオブジェクトへのポインタは、異なる型のオブジェクトへのポインタにキャストできますが、オブジェクトの宣言された型とは異なる型へのポインタを間接参照することは、ほとんど常に未定義の動作です。詳細は厳密なエイリアシングを参照してください。
|
ポインタを介してオブジェクトにアクセスする関数に、それらのポインタがエイリアスしないことを示すことが可能です。詳細はrestrictを参照してください。 |
(C99以降) |
配列型の左辺値式は、ほとんどのコンテキストで使用されると、配列の最初の要素へのポインタへの暗黙の変換を受けます。詳細は配列を参照してください。
char *str = "abc"; // "abc" is a char[4] array, str is a pointer to 'a'
charへのポインタは、しばしば文字列を表すために使用されます。有効なバイト文字列を表すには、ポインタはcharの配列の要素であるcharを指している必要があり、ポインタによって参照される要素のインデックス以上のあるインデックスにゼロ値のcharが存在する必要があります。
[編集] 参考文献
- C23標準 (ISO/IEC 9899:2024)
- 6.7.6.1 ポインタ宣言子 (p: TBD)
- C17標準 (ISO/IEC 9899:2018)
- 6.7.6.1 ポインタ宣言子 (p: 93-94)
- C11標準 (ISO/IEC 9899:2011)
- 6.7.6.1 ポインタ宣言子 (p: 130)
- C99標準 (ISO/IEC 9899:1999)
- 6.7.5.1 ポインタ宣言子 (p: 115-116)
- C89/C90標準 (ISO/IEC 9899:1990)
- 3.5.4.1 ポインタ宣言子
[編集] 関連項目
| C++ ドキュメント ポインタ宣言
|