ポインタの基本
メモリアドレスを直接操作する方法。C++の最重要概念
概要
ポインタは、 メモリのアドレス(記憶場所)を保存する変数です。
C++を本格的に理解するには、 ポインタの概念が不可欠です。 難しいかもしれませんが、 段階的に学べば必ず理解できます。
アドレスとの関係
まず、変数がメモリのどこに保存されているかを理解しましょう。
#include <iostream>
int main() {
int x = 42;
std::cout << "値: " << x << std::endl;
std::cout << "アドレス: " << &x << std::endl;
return 0;
}
値: 42
アドレス: 0x7ffc123a4ff4
&xは「xのアドレス」を意味します。
このアドレスはコンピュータのメモリ上での位置です。
ポインタの宣言と初期化
ポインタの作成
#include <iostream>
int main() {
int x = 42;
// ポインタの宣言と初期化
int* ptr = &x; // ptr は x のアドレスを保存
std::cout << "x の値: " << x << std::endl;
std::cout << "ptr の値(アドレス): " << ptr << std::endl;
return 0;
}
x の値: 42
ptr の値(アドレス): 0x7ffc123a4ff4
int* ptrは「int型へのポインタ」を意味します。
*がポインタの記号です。
ポインタのデリファレンス
ポインタが指す先の値を取得するには、 デリファレンス演算子 * を使います。
#include <iostream>
int main() {
int x = 42;
int* ptr = &x;
std::cout << "ポインタが指す値: " << *ptr << std::endl;
// ポインタを通じて値を変更
*ptr = 100;
std::cout << "x の値: " << x << std::endl;
return 0;
}
ポインタが指す値: 42
x の値: 100
重要:*ptrを変更すると、
元の変数xも変更されます。
ポインタと参照の関係
参照は「自動的にデリファレンスされるポインタ」と言えます。
| 参照 | ポインタ | |
|---|---|---|
| 宣言 | int & ref = x; |
int* ptr = &x; |
| 使用 | ref = 10; |
*ptr = 10; |
| 初期化 | 必須 | 任意 |
| null 可能 | 不可 | 可能 |
| 再割り当て | 不可 | 可能 |
ポインタの便利な使い方
例1: 複数の変数のアドレスを管理
#include <iostream>
int main() {
int a = 10, b = 20, c = 30;
int* ptrs[3] = {&a, &b, &c}; // ポインタの配列
for (int i = 0; i < 3; i++) {
std::cout << "値: " << *ptrs[i] << std::endl;
}
return 0;
}
値: 10
値: 20
値: 30
例2: ポインタを通じた値の交換
#include <iostream>
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
std::cout << "交換前: x=" << x << ", y=" << y << std::endl;
swap(&x, &y);
std::cout << "交換後: x=" << x << ", y=" << y << std::endl;
return 0;
}
交換前: x=10, y=20
交換後: x=20, y=10
nullptr:ヌルポインタ
ポインタが何も指していない場合、 nullptrを使います。
#include <iostream>
int main() {
int* ptr = nullptr; // 何も指していない
if (ptr == nullptr) {
std::cout << "ポインタは null です" << std::endl;
}
int x = 42;
ptr = &x; // 今、x を指す
if (ptr != nullptr) {
std::cout << "ポインタが指す値: " << *ptr << std::endl;
}
return 0;
}
ポインタは null です
ポインタが指す値: 42
メモリ可視化
ポインタの動作を理解するため、メモリ図を見てみましょう。
メモリアドレス 値 説明
0x1000 [42] 変数 x
0x1004 [0x1000] ポインタ ptr(x のアドレスを保存)
ptr が指す先 = x
*ptr デリファレンス = 42
ポインタと配列
配列の名前は、実は配列の最初の要素へのポインタです。
#include <iostream>
int main() {
int arr[3] = {10, 20, 30};
int* ptr = arr; // arr は &arr[0] と同じ
std::cout << ptr[0] << std::endl; // 10
std::cout << ptr[1] << std::endl; // 20
std::cout << *(ptr + 2) << std::endl; // 30
return 0;
}
10
20
30
ptr + 2は「ptr の指す位置から2つ先」を意味します。
ポイント
- ポインタはメモリアドレスを保存する変数
&(アドレス演算子)で変数のアドレスを取得*(デリファレンス演算子)でポインタが指す先の値を取得- nullptrで「何も指していない」を表現
- 配列は、実はポインタの特殊形態
よくある誤り
誤り1: 初期化されていないポインタを使う
int* ptr; // 初期化されていない
std::cout << *ptr << std::endl; // 危険!: ゴミ値
誤り2: nullptr をデリファレンス
int* ptr = nullptr;
std::cout << *ptr << std::endl; // クラッシュ
誤り3: ポインタと値を混同
int x = 42;
int* ptr = &x;
std::cout << ptr << std::endl; // アドレスが出力
std::cout << *ptr << std::endl; // 値が出力
やってみよう
練習1: 2つの変数のアドレスを表示するプログラム。
練習2: ポインタを使って2つの値を交換する関数。
練習3: 配列のポインタを使って要素にアクセス。
チャレンジ: ポインタ配列を使って複数の変数を管理。
まとめ
- ポインタは C++で最重要の概念
- メモリの直接操作が可能になり、パワーが大幅に増加
&と*の関係を深く理解- 安全性に注意(nullptr チェック、範囲確認)