C言語入門|アドレス専用の型:ポインタ

「場所」を入れるための特別な箱―

前の記事では、
& 演算子を使うことで 変数のアドレス(番地)を取得できる
ことを学びました。

ここで、多くの人が次のように考えます。

アドレスって符号なしの大きな数値だし、
unsigned long 型に入れればいいんじゃない?

一見すると正しそうですが、
この考え方には落とし穴 があります。

unsigned long 型にアドレスを入れると何が問題?

次の例を見てください。

unsigned long total_users = 5000000UL;      // ユーザー数
unsigned long server_id   = 1024UL;         // サーバ識別番号
unsigned long addr_server = (unsigned long)&server_id; // アドレス

3つとも unsigned long 型 ですが、中身の意味はまったく違います。

変数名中身の意味
total_users計算や比較に使う数値
server_id識別番号としての数値
addr_serverメモリ上の番地

ここが重要なポイントです。

  • unsigned long は 数値計算のための型
  • アドレスは 計算したり比較したりする対象ではない

にもかかわらず、
同じ型に入れてしまうと、こうなります。

unsigned long を使うことの弊害

問題点説明
意味が区別できない数値なのかアドレスなのか、コードを見ただけでは分からない。
誤った演算ができてしまう加算・減算・比較が文法上できてしまう。
バグの温床になるアドレスを数値として扱う事故が起きやすい。

つまり、

unsigned long に入るから安全
ではなく
入ってしまうから危険

なのです。

アドレスは「数値」ではなく「場所」

ここで考え方を切り替えましょう。

種類本質
数値大小比較・計算するもの
アドレスメモリ上の場所を示すもの

アドレスはたまたま
「大きな符号なし整数っぽい見た目」
をしているだけです。

意味が違うものは、型も分けるべき
これが C 言語の考え方です。

アドレス専用の型が用意されている

そこで登場するのが、
アドレスを格納するための専用の型 です。

C 言語では最初から用意されています。

アドレスを格納する型の書式

ポインタ型の基本形

書式意味
void* 変数名アドレス専用の変数を宣言する。

void* 型は、

  • 計算用の数値を入れる型ではない。
  • メモリの場所を示すためだけの型

です。

void* の void に惑わされないで

よくある誤解があります。

void って、関数の戻り値で使った void と同じ?

名前は同じですが、役割は別です。

用途意味
関数の void戻り値・引数が存在しない。
void*型未定のアドレスを格納する。

今回は
void *= アドレス専用の箱
と覚えてOKです。

サンプルプログラムで確認してみよう

unsigned long を使わず、
ポインタ型で正しく書いてみます。

プロジェクト名:9-6-1 ソースファイル名: sample9-6-1.c

#include <stdio.h>

int main(void)
{
    int level = 5;
    printf("現在のレベルは %d です。\n", level);

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

    return 0;
}

実行結果例

現在のレベルは 5 です。
level のアドレスは 0x7ffdd3a8c41c です。

※ アドレスは環境・実行ごとに変化します。

このプログラムで使っている命令

要素書式役割
& 演算子&変数変数の先頭アドレスを取得
void*void* 変数名アドレスを格納する
printfprintf(書式, 値)情報を表示
%p書式指定子アドレス表示専用
returnreturn 値main関数を終了

特に重要なのは %p です。
アドレス表示では 必ず %p を使う のがルールです。

ポインタとは何か

ここで整理しましょう。

項目内容
ポインタ型アドレスを格納する型
ポインタ変数アドレスを値として持つ変数
格納されるものデータそのものではない

ポインタは、

値を持つ箱ではなく
値がある場所を指す矢印

のような存在です。

まとめ:なぜ unsigned long ではダメなのか(まとめ)

観点unsigned longポインタ型
意味の明確さあいまい明確
計算の危険高い低い
可読性悪い良い
C言語らしさ低い高い

アドレスはアドレスとして扱う
これが C 言語の世界の基本ルールです。

次の一歩へ

ここまでで、

  • アドレスは & で取得する
  • アドレスは unsigned long に入れない
  • ポインタ型に格納する

という大切な考え方を身につけました。

次は、
ポインタが指している先の値を操作する方法
に進みます。

ここからが、C言語の本領発揮です。

この理解ができたあなたは、
もう 「アドレスを数値として扱わない」Cエンジニア です。

次は、
そのアドレスを使って 中身にアクセスする方法 に進みましょう。