Pointer declaration
ポインタは、別の型の関数またはオブジェクトを参照するオブジェクトの一種であり、修飾子を追加する可能性があります。ポインタは何も参照しないこともあり、これは特別なヌルポインタ値によって示されます。
目次 |
構文
宣言文法 において、ポインタ宣言の type-specifier シーケンスは指し示される型(関数型またはオブジェクト型であり、不完全型でも可)を指定し、 declarator は以下の形式を取ります:
*
attr-spec-seq
(オプション)
qualifiers
(オプション)
declarator
|
|||||||||
where 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; // エラー: キャストなしではpc経由でnを変更できません pc = NULL; // OK: pc自体は変更可能 int * const cp = &n; // cpは非const intへのconstポインタ *cp = 2; // cp経由でnを変更可能 // cp = NULL; // エラー: cp自体は変更不可 int * const * pcp = &cp; // 非const intへのconstポインタへの非constポインタ
attr-spec-seq (C23) は、宣言されたポインタに適用される 属性 のオプションのリストです。
説明
ポインタは間接参照に使用され、これは広く普及したプログラミング技術です。ポインタは参照渡しのセマンティクスを実装するため、動的 storage duration を持つオブジェクトへのアクセスに、「オプショナル」な型(nullポインタ値を使用)の実装に、構造体間の集約関係の実装に、コールバック(関数ポインタを使用)に、ジェネリックインターフェース(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へのポインタ
ポインタは
間接演算子
(単項
*
)のオペランドとして現れ、これが指し示すオブジェクトを識別する
lvalue
を返します:
int n; int* p = &n; // ポインタpはnを指している *p = 7; // nに7を格納する printf("%d\n", *p); // lvalueからrvalueへの変換によりnから値を読み取る
struct
および
union
型のオブジェクトへのポインタは、
ポインタを介したメンバアクセス
演算子
->
の左辺オペランドとしても使用できます。
配列からポインタへの 暗黙変換 により、配列の先頭要素へのポインタは配列型の式で初期化できます:
int a[2]; int *p = a; // a[0]へのポインタ int b[3][3]; int (*row)[3] = b; // b[0]へのポインタ
配列の要素へのポインタに対しては、特定の 加算、減算 、 複合代入 、 インクリメント、デクリメント 演算子が定義されています。
比較演算子 は、いくつかの状況においてオブジェクトへのポインタに対して定義されています:同じアドレスを表す2つのポインタは等しいと比較され、2つのヌルポインタ値は等しいと比較され、同じ配列の要素へのポインタはそれらの要素の配列インデックスと同じように比較され、構造体メンバーへのポインタはそれらのメンバーの宣言順に比較されます。
多くの実装では、ランダムな起源のポインタに対しても strict total ordering を提供します。例えば、連続した(「フラット」な)仮想アドレス空間内のアドレスとして実装されている場合などです。
関数へのポインタ
関数へのポインタは、関数のアドレスで初期化できます。 function-to-pointer 変換により、アドレス取得演算子はオプションです:
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 * を受け取り返すユーザー提供のコールバックを期待します。すべての場合において、使用前にポインタを正しい型に変換するのは呼び出し元の責任です。
ヌルポインタ
すべての型のポインタには、その型の nullポインタ値 と呼ばれる特別な値があります。値がnullのポインタは、オブジェクトや関数を指しません(nullポインタのデリファレンスは未定義動作です)。また、同じ型で値が null である他のすべてのポインタと等しいと比較されます。
ポインタをnullに初期化する、または既存のポインタにnull値を代入するには、nullポインタ定数( NULL または値がゼロの他の整数定数)を使用できます。 static initialization もポインタをnull値に初期化します。
ヌルポインタはオブジェクトが存在しないことを示す場合や、他の種類のエラー状態を示すために使用されることがあります。一般的に、ポインタ引数を受け取る関数は、値がヌルであるかどうかをチェックし、そのケースを別途処理する必要がほとんど常にあります(例えば、 free 関数はヌルポインタが渡された場合には何も行いません)。
注記
任意のオブジェクトへのポインタは異なる型のオブジェクトへのポインタに キャスト できますが、オブジェクトの宣言された型とは異なる型へのポインタを間接参照すると、ほぼ常に未定義動作となります。詳細は strict aliasing を参照してください。
|
ポインタを通じてオブジェクトにアクセスする関数に対して、それらのポインタがエイリアスではないことを示すことが可能です。詳細は restrict を参照してください。 |
(C99以降) |
配列型の左辺値式は、ほとんどの文脈で使用される際に、配列の最初の要素へのポインタへの 暗黙変換 を受けます。詳細は 配列 を参照してください。
char *str = "abc"; // "abc" は char[4] 配列であり、str は '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++ documentation
for
Pointer declaration
|