みえるCお試し版

トラック 11・ポインタ基礎

ポインタとは「宛先メモ」

読む目安 約10分 ねらい: ポインタを「番地を入れる変数」として説明でき、それが役に立つ3つの理由を言える

このレッスンの要点

  • ポインタは値そのものではなく、値の居場所(番地)を入れる変数
  • うれしいこと3つ:呼び出し元を書き換えられる・大きなデータを軽く渡せる・伸縮するデータ構造が作れる
  • 難しさの正体は「値」と「番地」の二段構えを同時に扱うこと
  • いまどちらの階の話をしているか、そのつど意識する

友達に本を届ける方法は2つあります。1つは本そのものを手渡す方法。もう1つは「その本は市立図書館の3階、棚B-12にあります」と書いたメモを渡す方法です。

C言語のポインタは、後者のメモです。中身そのものではなく、中身がどこにあるかを書いた紙切れ。それ以上でも以下でもありません。

番地を書いた宛先メモと、その先にあるロッカーのイラスト
番地を書いた宛先メモと、その先にあるロッカーのイラスト
ポインタ姫わたくしの郵便カバンに入っているのは、荷物ではなく宛先メモですのよ。番地さえ分かれば、どこへでも届けられますわ

ポインタは「番地を入れる変数」

前のトラックで、すべての変数には番地があると学びました。その番地も数値なので、変数に入れて持ち歩くことができます。番地を入れるための変数、それがポインタです。

int a = 5;      // 中身は 5
int *p = &a;    // 中身は 「a の番地」

p の中に 5 は入っていません。入っているのは 0x7ffd5a2c のような番地です。p は5の居場所を知っているだけで、5そのものは持っていません。

ビットうーん……番地を持っててもうれしくない気がするんだけど。5がほしいなら5を持てばいいのに

もっともな疑問です。答えを3つ挙げます。

うれしいこと①:相手の本体を書き換えられる

トラック7で、関数に変数を渡すとコピーが渡ると学びました(値渡し)。だから関数の中でいくら変数をいじっても、呼び出し元の変数は変わりません。ところが番地を渡せば、関数は本体そのものに手が届きます。これができないと、scanfのように「呼び出し元の変数に値を入れて返す」関数は作れません。

うれしいこと②:大きなものをコピーせずに渡せる

1000要素の配列を関数に渡すたびに全部コピーしていたら、時間もメモリも無駄です。番地なら、どれだけ大きなデータでも渡すのは8バイトぶんの数値ひとつで済みます。図書館ごと運ぶかわりに、棚の番号を伝えるわけです。

うれしいこと③:形の変わるデータを作れる

必要なぶんだけ箱を借り、それをメモでつないでいけば、あとから伸び縮みするデータ構造(連結リストなど)が作れます。これは第4部の主役です。

なぜ難しいと言われるのか

ポインタでつまずく原因は、実はポインタそのものではありません。「値」と「番地」の2階建てを、頭の中で同時に扱う必要があるからです。

p の話をしているのか、p が指している先の話をしているのか。この切り替えができれば、ポインタの9割は終わりです。だからこのトラックでは、常にメモリの図とメモの比喩を並べて進めます。

師範ポインタは難しいのではない。二段構えなだけじゃ。どちらの階の話をしておるか、そのつど声に出せばよい

まとめ

ポインタは値そのものではなく、値の居場所(番地)を入れておく変数です。相手の本体を書き換える・大きなデータを軽く渡す・形の変わるデータを作る、という3つの力を持ちます。次のレッスンから、番地を書く道具 & と、番地を訪ねる道具 * を手に取ります。

アプリでこのレッスンを動かして学ぶ(無料・登録なし)

動かして確かめるコード

#include <stdio.h>

int main(void) {
    int a = 5;
    int *p = &a;
    a = 9;
    printf("%d\n", a);
    return 0;
}

確認問題

確認問題 1

ポインタの説明として、もっとも正確なものはどれでしょう。

  1. 値そのものではなく、値が置かれている番地を入れておく変数
  2. 2つの変数を1つにまとめて扱うための特別な変数
  3. 変数どうしを矢印でつなぐための、C言語専用の記号
  4. 関数の返り値を2つに増やすための構文
答えを見る

正解: A(値そのものではなく、値が置かれている番地を入れておく変数)

ポインタは「番地を入れる変数」です。図では矢印で描きますが、実体は番地という数値にすぎません。結果として呼び出し元を書き換えられる(返り値の制限を超えられる)ようになりますが、それは使い道のひとつであって定義ではありません。

確認問題 2

int a = 5; int *p = &a; を実行したあと、p のロッカーに入っているものはどれでしょう。

  1. a の番地
  2. 5
  3. a という名前
  4. 5 のコピーと a の番地の両方
答えを見る

正解: A(a の番地)

p の中身は番地だけです。5 は a のロッカーに入ったままで、p はその居場所を知っているにすぎません。5 が欲しいときは *p と書いて、その番地を訪ねます。宛先メモには荷物は入っていない、と考えてください。

「ポインタ基礎」の目次

  1. ポインタとは「宛先メモ」
  2. & と *——住所を書く・訪ねる
  3. ポインタ変数の宣言と型有料版
  4. NULLポインタとnullptr(C23)有料版
  5. ポインタ経由の読み書き有料版
  6. 関数に変数を「参照渡し」する有料版
  7. ポインタと配列の深い関係有料版
  8. ポインタのよくある誤解トップ5有料版

この先へ ポインタ・メモリ・構造体・ファイル入出力まで、全26トラック・211レッスン・演習508問は有料版に入っている。

有料版(BOOTH)を見る

ほかのトラック

姉妹品: 手を動かして覚える Linux 教材 Linux とインフラの仕組みを地図で学ぶ

Web 版 / BOOTH