
C言語基礎|オブジェクトとアドレス
ポインタの前にここ!C言語は「値」より先に「場所(アドレス)」を理解すると一気にラクになる。
ポインタって聞くと、いきなり * やら & やらが出てきて「うっ…」となりがちですよね。
でも大丈夫。ポインタの正体は、実はすごく素朴で、
- オブジェクト(変数や配列の要素など)はメモリ上に置かれていて
- それぞれに 住所(アドレス) がある
- その住所を扱う仕組みがポインタ
…という流れなんです。
なのでまずは、ポインタの前段として「オブジェクトって何?」「アドレスって何?」を、ゆっくり丁寧に固めていきましょう。

オブジェクトとは(C言語でいう「置き場所つきのデータ」)
C言語でいう オブジェクト(object) は、ざっくり言うと
値を入れておける“実体”があって、メモリ上のどこかに置かれているもの
です。
オブジェクトに含まれる代表的な性質
| 性質 | 何のこと? | 例 |
|---|---|---|
| 型 | どう解釈するか | int, double など |
| 大きさ | 何バイト使うか | sizeof(int), sizeof(double) |
| アドレス | メモリ上の場所 | &n, &x |
| 記憶域期間 | いつからいつまで存在するか | 自動/静的/動的 など |
| 値 | 今入っている内容 | n = 10 など |
この中でも、ポインタに直結するのが アドレス です。
「バラバラな箱」から「メモリの一部」へ(図でイメージ)
これまで変数を「箱」として見てきたのは正しい理解です。ただし実際の世界では、その箱は メモリという大きな空間のどこかに並んで置かれています。
図:2つの見方(同じものを別の角度から)
図A:バラバラの箱として見る(直感)

図B:メモリ空間の一部として見る(実態)

※番地やサイズは環境で変わります。ここでは説明用の例です。
アドレスとは(オブジェクトの住所)
アドレス(address) は、
オブジェクトがメモリ上のどこに置かれているかを表す番地
のことです。
さっきの図Bだと、n の先頭が 1000 なら「n のアドレスは 1000」という感じです。
この「先頭」の意味も大事で、複数バイトにまたがる場合でも 代表として先頭アドレス をアドレスとして扱います。
sizeofで分かる「大きさ」とアドレスの関係
オブジェクトには大きさがあります。大きさがあるということは、メモリ上で 領域を占有します。
型の大きさの例(代表例)
| 型 | 大きさの例 | 備考 |
|---|---|---|
| char | 1バイト | ほぼ固定 |
| int | 4バイト | 多くの環境 |
| double | 8バイト | 多くの環境 |
※正確な値は処理系で変わるので、必ず sizeof で確認できます。
アドレス演算子 &(オブジェクトの住所を取り出す)
オブジェクトのアドレスを取り出すのが 単項の &(アドレス演算子) です。
単項 & 演算子(アドレス演算子)
| 書き方 | 意味 |
|---|---|
| &a | a のアドレス(a が置かれている場所) |
ここでの & は、ビットAND(2項演算子の &)とは別物です。
1つの値に対して使っていたらアドレス演算子、2つの値を並べていたらビットAND、という見分けが基本になります。
サンプルプログラム
「変数と配列要素のアドレス」を表示して、配列が連続して並ぶ雰囲気もつかむシンプルな例です。
プロジェクト名:chap10-2-1 ソースファイル名:chap10-2-1.c
#include <stdio.h>
int main(void)
{
int score = 10;
double rate = 1.25;
int data[3] = {100, 200, 300};
puts("メモリ上の住所(アドレス)を確認します。");
printf("score のアドレス : %p\n", (void *)&score);
printf("rate のアドレス : %p\n", (void *)&rate);
printf("data[0]のアドレス : %p\n", (void *)&data[0]);
printf("data[1]のアドレス : %p\n", (void *)&data[1]);
printf("data[2]のアドレス : %p\n", (void *)&data[2]);
return 0;
}実行結果のイメージ(例)
メモリ上の住所(アドレス)を確認します。
score のアドレス : 0x7ffd2c9a1a3c
rate のアドレス : 0x7ffd2c9a1a30
data[0]のアドレス : 0x7ffd2c9a1a20
data[1]のアドレス : 0x7ffd2c9a1a24
data[2]のアドレス : 0x7ffd2c9a1a28アドレスの値や桁数、並び方は環境で変わります。
ただし配列は多くの場合、要素が連続して並び、int なら 4バイト刻みっぽく増えるのが見えてきます。
表示に使った命令(関数)と書式、何をする?
ここで出てきた命令(関数)は puts と printf です。
puts
- 書式:puts(文字列);
- 何をする?:文字列を表示し、最後に改行も出します
- 特徴:シンプルに1行出すのが得意
printf
- 書式:printf(書式文字列, 引数1, 引数2, ...);
- 何をする?:書式に合わせて値を表示します
- 例:printf("score のアドレス : %p\n", (void *)&score);
%p と (void *) の意味(アドレス表示の作法)
アドレスを表示するときの変換指定は %p です。p は pointer 由来です。
なぜ (void *) にキャストしているの?
printf の %p は、「ポインタ値(アドレス)を表示する」ための指定です。
Cでは %p に渡す値は void * 型 に合わせるのが作法なので、(void *)&score のように書くと安全で読みやすいです。
%p のポイント
| 項目 | 内容 |
|---|---|
| 変換指定 | %p |
| 渡す値 | (void *) にしたポインタ(例:(void *)&score) |
| 表示形式 | 多くの環境で16進数っぽい見た目 |
配列要素のアドレスが「規則的」に増える理由
配列は基本的に 同じ型の要素が連続して並ぶので、要素のアドレスはだいたい次の関係になります。
- &data[1] は &data[0] より int 1個分 だけ後ろ
- &data[2] は &data[1] より int 1個分 だけ後ろ
図:配列は横並び(連続領域)

この「連続して並ぶ」が、次に学ぶ ポインタ演算 や 配列とポインタの関係 に効いてきます。
注意:register 変数は & できない(古典ルール)
古いCの考え方では、register 指定された変数は「レジスタに置くかも」なので、メモリ上の住所が取れない扱いになり、& を付けるとエラーになり得ます。
ただ、最近のコンパイラでは最適化の都合もあり、register 自体あまり使われません。
試験や文法として「&できないことがある」を知っておく、くらいでOKです。
まとめ(ここが腹落ちするとポインタが楽)
- オブジェクトはメモリ上の実体で、性質として 型・大きさ・アドレス を持つ
- アドレスは「置かれている場所(番地)」
- アドレスは & で取り出せる。
- 表示は %p を使い、(void *) にキャストして渡すのが作法
- 配列要素は連続して並ぶので、アドレスが規則的に増える。
