C++におけるポインタ(Pointers)は、非常に強力で重要な概念です。ポインタは、メモリ上のアドレスを操作するために使用され、C++プログラムの効率を大きく向上させることができます。しかし、その使用には注意が必要です。この記事では、C++のポインタについて完全かつ包括的に説明します。
ポインタの基本
ポインタとは、他の変数のメモリアドレスを格納するための変数です。ポインタ変数自体が格納しているのは、通常の変数の値ではなく、その変数がメモリ内でどこに格納されているかというアドレスです。

ポインタの宣言
ポインタを宣言するには、通常の変数宣言に加えて、型の後にアスタリスク(*
)を付けます。例えば、整数型のポインタを宣言するには以下のように記述します:
cppint *ptr;
このコードでは、ptr
はint
型のデータのアドレスを格納するポインタ変数であることを意味します。
ポインタの初期化
ポインタは初期化しないと不定のメモリアドレスを指すことになり、未定義動作が発生する可能性があります。ポインタを初期化するには、変数のアドレスを代入します。例えば、次のように書きます:
cppint x = 10;
int *ptr = &x;
ここで、&
は「アドレス演算子」と呼ばれ、変数x
のメモリ内でのアドレスを取得します。これにより、ポインタptr
はx
のアドレスを指すようになります。
ポインタの操作
ポインタを使ってメモリを操作する方法には、以下の2つの主要な操作があります:
-
間接参照(デリファレンス)
ポインタが指すアドレスに格納されている実際の値にアクセスするためには、*
を使用します。これを「デリファレンス」と呼びます。cppint x = 10; int *ptr = &x; std::cout << *ptr << std::endl; // 10が出力される
上記のコードでは、
*ptr
によってptr
が指すアドレス(つまりx
のアドレス)に格納されている値を参照しています。 -
アドレスの変更
ポインタを使って他の変数のアドレスを参照することができます。たとえば、次のようにポインタを変更することができます:cppint y = 20; ptr = &y; // ptrはyのアドレスを指すようになる std::cout << *ptr << std::endl; // 20が出力される
ポインタと配列
C++では、配列名自体がその配列の最初の要素のアドレスを示します。これにより、配列とポインタは密接に関連しています。例えば、次のように配列の要素にアクセスできます:
cppint arr[] = {1, 2, 3, 4, 5};
int *ptr = arr; // arrは配列の最初の要素のアドレスを持つ
std::cout << *ptr << std::endl; // 1が出力される
ptr++; // ポインタを1つ進める
std::cout << *ptr << std::endl; // 2が出力される
ここでは、ポインタptr
が配列arr
の最初の要素を指し、ポインタをインクリメントすることで次の要素を指すようになります。
ダブルポインタ
ダブルポインタ(**
)は、ポインタがポインタのアドレスを指すような場合に使用されます。例えば、次のように宣言できます:
cppint x = 10;
int *ptr = &x;
int **ptr2 = &ptr;
ここで、ptr2
はptr
を指すポインタです。この場合、**ptr2
を使用するとx
の値にアクセスできます。
ポインタと動的メモリ管理
C++では、動的メモリ管理を行うためにポインタを使用します。new
演算子とdelete
演算子を使って、動的にメモリを割り当てたり解放したりすることができます。
-
動的メモリの割り当て
new
演算子を使うことで、ヒープ領域にメモリを動的に割り当てることができます:cppint *ptr = new int; // int型のメモリを1つ動的に割り当て *ptr = 10; // 値を代入 std::cout << *ptr << std::endl; // 10が出力される
-
メモリの解放
delete
演算子を使うことで、動的に確保したメモリを解放します:cppdelete ptr; // ptrが指すメモリを解放
配列の場合は、
delete[]
を使います:cppint *arr = new int[5]; // 配列の動的割り当て delete[] arr; // 配列のメモリを解放
ポインタと関数
ポインタは関数に引数として渡すことで、関数内で引数を変更することができます。これを「参照渡し」と呼びます。
cppvoid increment(int *ptr) {
(*ptr)++;
}
int main() {
int x = 5;
increment(&x);
std::cout << x << std::endl; // 6が出力される
}
この例では、increment
関数がx
のアドレスを受け取り、ポインタを通じてx
の値を変更しています。
ポインタの注意点
ポインタを扱う際にはいくつかの注意点があります。
-
ヌルポインタ(Null Pointer)
ポインタは、メモリを指していない場合、nullptr
(C++11以降)を代入することが一般的です。ヌルポインタにアクセスしようとすると、実行時エラーが発生します。cppint *ptr = nullptr; // *ptr = 10; // これは実行時エラーになります
-
ダングリングポインタ
メモリが解放された後もそのメモリのアドレスを保持しているポインタをダングリングポインタと言います。これにアクセスしようとすると未定義動作が発生します。ポインタを解放した後は、nullptr
を代入しておくと安全です。 -
ポインタの初期化を忘れない
ポインタを宣言した後、初期化しないと不定の値が格納され、バグの原因となります。
結論
ポインタはC++の強力で重要な機能の一部であり、メモリの効率的な管理や、データの直接操作を可能にします。しかし、ポインタを扱う際は慎重に行動し、正しく使用することが重要です。ポインタに関する基本的な概念から、高度なテクニックまでを理解することで、C++プログラムのパフォーマンスを向上させることができます。