C言語入門|アドレスから値を取り出すしくみ

ポインタが「中身」に変わる瞬間

前の節では、
変数のアドレスを & 演算子で取得し、ポインタ型の変数に格納できる
というところまで学びました。

ここで、誰もが次の疑問を持ちます。

アドレスを手に入れたけど、
それで何ができるんですか?

答えはシンプルです。

アドレスを使って、メモリの中身を直接読み取れる。

これこそが、C言語が「低水準」と呼ばれる理由のひとつです。

アドレスから情報を取り出すための演算子

メモリ上の指定番地に書き込まれている値を取り出すには、
次の構文を使います。

間接演算子(デリファレンス演算子)

書式意味
*ポインタ変数ポインタが指す番地の中身を取り出す。

この * 演算子は、

  • ポインタ変数に格納されているアドレスを使って
  • その番地にある情報を読み取り
  • 値として振る舞う(値に化ける)

という働きをします。

まずは全体像を確認するサンプルプログラム

次のプログラムを見てください。
あえてコンパイルエラーが出る例 から始めます。

#include <stdio.h>

int main(void)
{
    int score = 85;
    printf("スコアは %d 点です。\n", score);

    void* addrScore = &score;
    printf("score のアドレスは %p です。\n", addrScore);

    printf("%p 番地の中身は %d です。\n", addrScore, *addrScore);

    return 0;
}

プログラムの流れをメモリ視点で追ってみよう

ここからが本番です。
1行ずつ、メモリの中で何が起きているか を見ていきましょう。

① 変数が生まれる

int score = 85;

この行で行われていることは次のとおりです。

処理内容
メモリ確保int 型 4バイト分の領域を確保
初期化その領域に 85 を書き込む

仮に、score が次の番地に配置されたとします。

メモリのイメージ(例)
番地01234567
400085
40084000

② アドレスを取得してポインタに入れる

void* addrScore = &score;

この1行では、実は次の3つが同時に行われています。

手順内容
(1)score の先頭アドレスを調べる。
(2)ポインタ変数 addrScore を作る。
(3)調べた番地を addrScore に代入する。

メモリ状態(イメージ)

変数番地中身
score400085
addrScore40084000

addrScore は
score の値ではなく、score の場所を指している
ことがポイントです。

いよいよ * 演算子の出番

問題の行がこちらです。

*addrScore

この式の意味を、日本語で正確に書くとこうなります。

addrScore に入っている番地を使って
その番地に格納されている値を取り出す

addrScore の中身は 4000
つまり、

4000 番地の中身を読め

という命令になります。

気づいた人は鋭い

ここで、こう思いませんでしたか?

あれ?
*addrScore って、score と同じじゃない?

その通りです。

表現意味
score4000 番地に入っている値
*addrScore4000 番地に入っている値

同じメモリを、別の書き方で表しているだけ なのです。

これが、

*addrScore は score の別名

と言われる理由です。

ではなぜ、このプログラムはエラーになるのか?

ここまでの説明を読むと、
「ちゃんと 85 が表示されそう」
と思うかもしれません。

しかし、実際にはコンパイルエラーになります。

理由は void 型の制限 にあります。

void* 型では中身のサイズがわからない

コンパイラの立場で考えてみましょう。

コンパイラの疑問内容
どこから?addrScore が指す先頭番地
どこまで?何バイト分読むの?

void* 型は、

  • アドレスであることは分かる。
  • しかし その先にあるデータ型が分からない

という特徴を持っています。

void* 型の限界

項目内容
できることアドレスを保持する
できないこと中身のサイズを判断する
結果* を使うとコンパイルエラー

つまり、

先頭番地は分かるけど、
何バイト読めばいいのか分からない

これがエラーの正体です。

ここまでの理解が超重要

この節で、必ず押さえておいてほしいポイントを整理します。

ポイント内容
& 演算子変数の先頭アドレスを取得する。
* 演算子指定番地の中身を取り出す。
ポインタ「値」ではなく「場所」を扱う。
void*アドレスは持てるが中身は扱えない。

ここまで理解できたなら、
ポインタ学習の第一関門は突破 です。

次に進む前のひとこと

次の記事では、

  • void* ではなく
  • 「どの型のデータか分かるポインタ」

を使って、
安全に * 演算子を使う方法 を学びます。

そこから、
ポインタは一気に「便利な道具」へと変わります。

ここまで来たあなたは、
「アドレス」と「値」を頭の中で行き来できる段階 に到達しています。

次は、
いよいよ 型付きポインタの世界 です。