一覧へ

ポインタとメモリのアドレス

ポインタとは何か、メモリのアドレスがなぜ重要なのか、そして高級言語における参照がポインタとどのように異なるのかを学びます。

中級
|
12
|
検証済み (2026-07)
ポインタメモリのアドレス参照間接アクセスNULLポインタ
進捗0/23 (0%)

ポインタとメモリのアドレス

このトピックを終えると

ポインタが「メモリのアドレスを格納する変数」であること、そしてそれがコンピュータサイエンスにおいてなぜ重要なのか、高水準言語ではどのように隠されているのかを理解できるようになります。


変数はどこにあるのか

プログラムが実行されると、変数はメモリに格納されます。メモリはバイト単位で番号付けされています。この番号がメモリのアドレスです。

text
メモリのアドレス:  0x1000  0x1004  0x1008  0x100C
             ┌──────┐┌──────┐┌──────┐┌──────┐
             │  42  ││  7   ││ 'A'  ││  0   │
             └──────┘└──────┘└──────┘└──────┘
              変数 a   変数 b   変数 c   変数 d

a = 42と記述すると、コンピュータはメモリのどこかに42を格納し、aという名前をそのアドレスに関連付けます。私たちはアドレスを気にする必要はなく、aという名前を使うだけで済みます。


ポインタ - アドレスを格納する変数

通常の変数はを格納します。ポインタは別の変数のアドレスを格納します。

c
int a = 42;       // aに42を格納
int *p = &a;      // pにaのアドレスを格納

printf("%d\n", a);    // 42 (aの値)
printf("%p\n", p);    // 0x1000 (aのアドレス)
printf("%d\n", *p);   // 42 (pが指す場所の値)
text
変数 a          ポインタ p
┌──────────┐   ┌──────────┐
│    42    │   │  0x1000  │──→ aを指す
└──────────┘   └──────────┘
アドレス: 0x1000    アドレス: 0x2000
  • &a - aのアドレスを取得(アドレス演算子)
  • *p - pが指す場所の値を取得(間接参照)

なぜポインタが必要なのか

1. 大きなデータを効率的に渡す

1,000万個の数値を持つ配列を関数に渡すとします。配列全体をコピーすると、メモリと時間が無駄になります。アドレスだけを渡せば、元のデータに直接アクセスできます。

2. 動的なデータ構造

連結リスト、ツリー、グラフ - これらのデータ構造は、「次のノードの位置」を格納する必要があります。その「位置」がポインタです。

text
ノード A              ノード B              ノード C
┌────┬────────┐   ┌────┬────────┐   ┌────┬──────┐
│ 10 │ 0x2000 │──→│ 20 │ 0x3000 │──→│ 30 │ NULL │
└────┴────────┘   └────┴────────┘   └────┴──────┘

3. 関数で元のデータを修正する

c
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int x = 10, y = 20;
swap(&x, &y);
// x = 20, y = 10

ポインタなしで値をコピーして渡すと、関数内で値を変更しても元のデータは変更されません。ポインタでアドレスを渡さないと、元のデータを修正できません。


危険なポインタ

ヌルポインタ

c
int *p = NULL;
printf("%d", *p);  // クラッシュ!(Segmentation Fault)

何も指していないポインタを間接参照すると、プログラムがクラッシュします。これがヌルポインタの間接参照 - 歴史上最もコストのかかるバグの1つです。

ダングリングポインタ

c
int *p = malloc(sizeof(int));
*p = 42;
free(p);        // メモリを解放
printf("%d", *p);  // すでに解放されたメモリ - 予測不可能

freeでメモリを解放した後に、そのアドレスにアクセスすると、運が良ければゴミの値が出力され、運が悪いとクラッシュします。


高水準言語におけるポインタ

Python、JavaScript、Javaなどの高水準言語では、ポインタを直接扱うことはできません。しかし、**参照(reference)**という名前で、同じ概念が使用されています。

python
# Pythonにおける参照
a = [1, 2, 3]
b = a # bは同じリストを「参照」
b.append(4)
print(a) # [1, 2, 3, 4] - 元のデータも変更される

Pythonの変数は、実際にはポインタです。ただし、&*などの構文はなく、メモリのアドレスを直接操作することはできません。以前のPythonのトピック(可変オブジェクトの参照伝播)で扱った問題が、まさにこれです。

CポインタPython参照
アドレスへの直接アクセス可能不可能
ポインタ演算可能 (p + 1)不可能
NULLクラッシュ可能None → AttributeError
メモリの手動解放必須 (free)自動(ガベージコレクション)

高水準言語は、ポインタを隠蔽し、安全にしたものです。その代償として、メモリを直接制御する能力を犠牲にします。


結論

ポインタはメモリのアドレスを格納する変数です。 大きなデータの転送、動的なデータ構造、元のデータの修正 - これらの3つの理由から、ポインタが必要になります。 Python/JavaScriptの「参照」は、ポインタを安全に包んだもの - アドレス操作はできませんが、同じ原理で動作します。

💬 質問・コメント

0件のコメント

ログインせずに投稿できます。ゲスト投稿は投稿者自身で編集・削除できません。

0/2000

読み込み中...