ポインタ宣言
ポインタは別の型 (修飾を追加しても構いません) のオブジェクトまたは関数を参照するオブジェクトの型です。 ポインタは何も参照しないこともあります (これは特別なヌルポインタ値によって表されます)。
目次 |
[編集] 構文
ポインタ宣言の宣言の文法では、型指定子の並びは指す先の型 (関数型またはオブジェクト型、不完全でも構いません) を指示し、宣言子は以下の形式を持ちます。
* qualifiers(オプション) declarator
|
(1) | ||||||||
declarator は宣言中のポインタを名付ける識別子でも構いませんし、別のポインタ宣言子でも構いません (その場合はポインタへのポインタを表します)。
float *p, **pp; // p は float へのポインタです。 // pp は float へのポインタへのポインタです。 int (*fp)(int); // fp は int(int) 型の関数へのポインタです。
*
と識別子 (または別のネストした宣言子) の間に現れる qualifiers は、宣言中のポインタの型を修飾します。
int n; const int * pc = &n; // pc は const int への const でないポインタです。 // *pc = 2; // エラー、 p を通して n を変更することは (キャストなしでは) できません。 pc = NULL; // OK、 pc 自体は変更できます。 int * const cp = &n; // cp は const でない int への const ポインタです。 *cp = 2; // OK、 cp を通して n を変更できます。 // cp = NULL; // エラー、 cp 自体は変更できません。 int * const * pcp = &cp; // const でない int への const ポインタへの const でないポインタ。
[編集] 説明
ポインタは間接参照のために使用されます。 間接参照は普遍的なプログラミングテクニックです。 参照渡しの意味論を実装したり、動的記憶域期間を持つオブジェクトにアクセスしたり、「オプショナルな」型 (ヌルポインタ値を用いて)、構造体間の集約関係、コールバック (関数へのポインタを用いて)、型総称なインタフェース (void へのポインタを用いて) 等々、様々なものを実装したりするために使用できます。
[編集] オブジェクトへのポインタ
オブジェクトへのポインタはオブジェクト型 (不完全でも構いません) の式にアドレス取得演算子を適用した結果で初期化できます。
int n; int *np = &n; // int へのポインタ。 int *const *npp = &np; // const でない int への const ポインタへの const でないポインタ。 int a[2]; int (*ap)[2] = &a; // int の配列へのポインタ。 struct S { int n; } s = {1} int* sp = &s.n; // s のメンバを指す、 int へポインタ。
ポインタは間接参照演算子 (単項の *
) の被演算子として使用でき、その指す先のオブジェクトを識別する左辺値を返します。
int n; int* p = &n; // ポインタ p は n を指します。 *p = 7; // n に 7 を格納します。 printf("%d\n", *p); // 左辺地から右辺値への変換により、 n から値が読み込まれます。
構造体型および共用体型のオブジェクトへのポインタはポインタを通したメンバアクセス演算子 ->
の左側の被演算子としても使用できます。
配列からポインタへの暗黙の変換のため、配列の最初の要素へのポインタは配列型の式から初期化できます。
int a[2]; int *p = a; // a[0] へのポインタ。 int b[3][3]; int (*row)[3] = b; // b[0] へのポインタ。
特定の加算、減算、複合代入、インクリメントおよびデクリメント演算子が、配列の要素へのポインタに対して定義されます。
比較演算子はいくつかの状況でオブジェクトへのポインタに対して定義されます。 同じアドレスを表す2つのポインタは等しくなります。 2つのヌルポインタ値は等しくなります。 同じ配列の要素へのポインタの比較はその要素への配列インデックスの比較と同じです。 構造体メンバへのポインタの比較はそのメンバの宣言の順番になります。
多くの処理系はランダムオリジンなポインタ間の狭義全順序も提供します (例えば連続的な(「フラットな」) 仮想アドレス空間内のアドレスとして実装されている場合など)。
[編集] 関数へのポインタ
関数へのポインタは関数のアドレスで初期化できます。 関数からポインタへの変換のため、アドレス取得演算子は省略できます。
void f(int); void (*pf1)(int) = &f; void (*pf2)(int) = f; // &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; // ポインタ p は f を指しています。 (*p)(); // 関数指示子を通して関数 f が呼ばれます。 p(); // 直接ポインタを通して関数 f が呼ばれます。
等価比較演算子が関数へのポインタに対して定義されます (同じ関数を指している場合に等しくなります)。
関数型の互換性は関数引数のトップレベルの修飾子を無視するため、引数のトップレベルの修飾子だけが異なる関数へのポインタは相互交換可能です。
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* から void* への変換。 int* p2 = pv; // void* から int* への変換。 printf("%d\n", *p2); // 1 を表示します。
void へのポインタは未知の型のオブジェクトを渡すための使用されます。 これは型総称のインタフェースでは一般的です。 malloc は void* を返し、 qsort は2個の const void* 引数を取るユーザ提供コールバックを期待します。 pthread_create は void* を取って void* を返すユーザ提供コールバックを期待します。 すべての場合において、そのポインタを使用前に正しい型に変換するのは呼び出し元の責任です。
[編集] ヌルポインタ
すべての型のポインタには、その型のヌルポインタ値と呼ばれる、特別な値があります。 値がヌルであるポインタはオブジェクトや関数を指しません (ヌルポインタを逆参照することは未定義動作です)。 値がヌルであるポインタはその型の値がヌルであるすべてのポインタと等しくなります。
ポインタをヌルに初期化するまたは既存のポインタにヌル値を代入するために、ヌルポインタ定数 (NULL またはゼロの値を持つ任意の整数定数) を使用できます。 静的初期化もポインタをヌル値に初期化します。
ヌルポインタは、オブジェクトが存在しないことを示したり、その他のエラー状態を示すために使用できます。 一般的には、ポインタ引数を受け取る関数は、ほとんど必ず、値がヌルかどうかを確認し、その場合に異なる処理をする必要があります (例えば、 free はヌルポインタが渡されたときは何もしません)。
[編集] ノート
オブジェクトへのあらゆるポインタは異なる型のオブジェクトへのポインタにキャストできますが、そのオブジェクトの宣言された型と異なる型へのポインタを逆参照することは、ほとんど必ず未定義動作です。 詳細については厳格なエイリアシングを参照してください。
ポインタを通してオブジェクトをアクセスする関数に、それらのポインタがエイリアスしないと示すことができます。 詳細については restrict を参照してください。 |
(C99以上) |
配列型の左辺値式は、ほとんどの文脈では、その配列の最初の要素を指すポインタへの暗黙の変換が行われます。 詳細については配列を参照してください。
char *str = "abc"; // "abc" は char[4] の配列であり、 str は 'a' を指すポインタです。
char へのポインタはよく文字列を表すために使用されます。 有効なバイト文字列を表すためには、ポインタは char の配列の要素である char を指していなければならず、そのポインタが指す先の要素のインデックスより大きいまたは等しい何らかのインデックスに値ゼロを持つ char が存在しなければなりません。