0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

変数を「箱」で考えるのをやめたら、ポインタが急にわかった話

0
Last updated at Posted at 2026-02-27

プログラミング言語を学び始めると、たいていの教科書にはこう書いてある。

変数とは、値を入れる「箱」です。

最初のうちはこれで問題ない。int hp = 10; なら「hp という箱に 10 を入れた」でちゃんと動く。

でも、ポインタに入った瞬間このモデルが崩壊する。

「箱モデル」がポインタで壊れる瞬間

箱モデルだとこうなる。変数は箱で、箱の中に値が入っていて、ポインタは箱の場所を持っている。
ここまではまだ耐えられる。

でも問題はここから。

ポインタも「変数」なんだ。

int *p;

これも箱になる。じゃあその箱の中には何が入っているのか。住所(数値)だ。

すると世界はこうなる。

箱の中に住所が入っていて、その住所の先にも箱がある。

ここで多くの人の脳が軽くクラッシュする。「え、箱の中に箱の場所? じゃあ * って何?」となる。

三丁目の田中さん家で考える

ここで街のたとえ話に乗り換えよう。

街がある。それがメモリ全体だ。
三丁目1番地、三丁目2番地……と住所が並んでいる。それがメモリアドレスだ。

ある一軒家がある。

三丁目5番地に、田中さんが住んでいる。
家の中には貯金10万円がある。

Cで言うとこうなる。

  • 三丁目5番地 = 0x3005(メモリアドレス)
  • 田中さん = tanaka(変数名)
  • 家の中身(貯金10万円) = 100000(値)

ここで大事なことがある。

「tanaka」は家の中身ではない。「tanaka」は三丁目5番地の「表札」だ。

0x3005(三丁目5番地)
┌──────────┐
│  100000  │  ← 貯金(値)
└──────────┘
     ↑
  tanaka  ← 田中さん家という表札(ラベル)

&tanaka はその家の住所(番地)だ。0x3005 という数値そのものだ。

ではポインタは何か?

ポインタはこうだ。「三丁目5番地」と書かれたメモ。それ自体も、どこか別の家に置いてある。

int *sato = &tanaka;
0x3005(三丁目5番地) 田中さん家(tanaka)
┌──────────┐
│  100000  │  ← 貯金
└──────────┘

0x3008(三丁目8番地) 佐藤さん家(sato)
┌──────────┐
│  0x3005  │  ← 「三丁目5番地」と書かれた紙
└──────────┘

佐藤さんは田中さんの住所を知っている。だから直接乗り込んで貯金を書き換えられる。

  1. 佐藤さん家にある紙を見る → 三丁目5番地と書いてある
  2. そこへ行く
  3. 田中さんの貯金を書き換える
*sato = 200000; //書き換える

直接侵入だ。合法的な。

佐藤さん家にある紙をたどって、田中さん家の中身を書き換えた。番地をたどっているだけ。
こう見ると、構造はシンプルで壊れない。

変数はラベルだった

箱という概念を一度捨てよう。

実行中のメモリというのは、ただの番地付きの連続した領域だ。何もない。ただ並んでいるだけ。

アドレス    中身(4バイト)
-------------------------------
0x3005     100000

ここにコードが関わる。

int tanaka = 100000;

これでやっていることは3つ。

  1. メモリ上のどこかに 4バイトの領域を確保する
  2. そこに「tanaka」という名前(ラベル)を貼る
  3. 100000 を書き込む

つまり、変数は「中身」じゃなく「場所につけた名前」だ。

&tanaka は「tanaka というラベルが貼られた場所の番地」。つまり 0x3005 という数値。

そしてポインタはその番地を保持するための変数、つまり別の場所に貼られた別のラベルに過ぎない。

0x3008     0x3005    ← tanaka の番地が入っている
   ↑
  sato  ← sato もただのラベル

*sato は「sato の中身(= 0x3005)を番地として扱って、そこの中身を触る」という操作。
番地をたどっているだけ。魔法は何もない。

値渡しとポインタ渡しは物理的に全然違う

街のたとえでもう一つ確認しよう。

int yamada = tanaka;

これは「三丁目9番地に、田中さん家と同じ10万円をコピーして別の家を建てる」という行為だ。

0x3005(三丁目5番地) 田中さん家(tanaka)
┌──────────┐
│  100000  │
└──────────┘

0x3009(三丁目9番地) 山田さん家(yamada)
┌──────────┐
│  100000  │  ← 同じ値だが、住所は違う
└──────────┘

住所は違う。中身は同じ。だから yamada を書き換えても tanaka は変わらない。

ポインタを渡すのと値を渡すのは、物理的に全然違う行為だ。

コードで確認する

#include 

void kaizan(int *sato) {
    *sato = 10000000;  // 1000万に書き換える
}

int main(void) {
    int tanaka = 100000;  // 田中さんの貯金10万円
    kaizan(&tanaka);
    printf("現在の貯金は%d円\n", tanaka);  // 10000000 と表示される
}

これをメモリの平面で追いかけるとこうなる。

int tanaka = 100000; の時点

0x3005     100000
   ↑
  tanaka

kaizan(&tanaka) を呼ぶ時点

&tanaka = 0x3005 を関数に渡す。関数のスタック上に新しい領域ができる。

0x3005     100000   ← tanaka の実体(田中さん家)
0x3008     0x3005   ← sato(渡された番地を保持する別の家)

*sato = 10000000; の実行

CPUがやっていること:

  • sato(= 0x3008)の中身を読む → 0x3005
  • 0x300510000000 を書く
0x3005     10000000  ← 書き換わった
0x3008     0x3005

④ main に戻る

tanaka は依然として 0x3005 のラベル。その中身は 10000000。だから printf10000000 を出す。

kaizantanaka という名前を一切知らない。
ただ「渡された番地の中身を書き換えた」だけ。田中さんの住所だけを知っていた。

コンパイル時と実行時は別の世界

もう一個重要なことがある。コードの上下=実行順ではない、という話だ。

kaizanmain より上に書いてある。でも tanaka はまだ存在していない。矛盾しないのか?しない。

コンパイル時にコンパイラがやることは「設計図の登録」だ。

  • kaizanint* を受け取る関数として登録
  • 型チェックをして「問題なし」と確認

この段階では実際のメモリ番地はまだ決まっていない。tanaka0x3005 になるかどうかも、まだ誰も知らない。

実行時に初めてメモリが動く。

  • main がスタートする
  • int tanaka = 100000; でスタックに領域が確保されて tanaka0x3005 になる
  • kaizan(&tanaka) でその番地が渡される

さらに言うと、コンパイルが終わった後、tanaka という名前はバイナリから消える。CPUは番地しか見ない。

「tanaka」は人間のための便利装置だ。機械は 0x3005 しか知らない。

コードを書くとき、人間は名前の世界で考える。CPUは番地の世界で動く。ポインタはその境界にある概念だ。

まとめると

  • 変数 = メモリ上の領域につけた名前(住所に貼られたラベル)
  • &tanaka = そのラベルが指す場所の番地(田中さん家の住所)
  • ポインタ = 番地を保持するための変数(「三丁目5番地」と書かれたメモを持つ別の家)
  • *sato = sato の中身を番地として、そこの中身を触る操作(メモを見て、その住所に侵入する)
  • 値渡し = 中身をコピーして別の家を建てる(住所は別、中身は同じ)

箱で考えると「箱の中に箱の場所がある」という謎構造になる。

街と住所で考えると「ただの住所録と番地たどり」になる。

コンピュータに箱は存在しない。あるのは連続した数値の並びと、それを指す番地だけだ。型は「このビット列をどう読むか」という約束に過ぎない。

この視点まで来ると、二重ポインタも、関数ポインタも、スタックとヒープの違いも、全部「番地遊び」として見えてくる。

世界は意外と単純だった。複雑に見えるのは、説明が箱モデルに寄りすぎているせいだったりする。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?