プログラミングのポインタをわかりやすく解説【C言語】
- 作成日: 2021-04-07
- 更新日: 2023-12-24
- カテゴリ: プログラミング
ポインタとは?
プログラミングで使われるポインタとはいったいどういうものなのでしょうか?
特にC/C++などの言語ではこのポインタの理解が必須です。
ポインタを知らないとC/C++ではうまいようにプログラムを作ることが出来ません。
結論から言うと、ポインタとは「スイッチの付いた箱」のことです。
スイッチを切り替えることでアクセスするデータを変更することができます。
このスイッチの切り替えの概念が、初心者の人にはうまく理解できないんだと思います。
この記事では、プログラミングのポインタについてわかりやすく解説します。
ポインタの綴りと意味
ポインタはpointer
と英語では呼ばれます。
これの意味は「さす人」とか「さし棒」という意味です。
何かを指し示すのがポインタということですね。
ポインタはスイッチの付いた箱
ポインタの概念について解説します。
まず、小さな箱をイメージしてください。
箱の横側にはON/OFFを切り替えるスイッチが付いています。
そして、その箱からは尻尾のような矢印が飛び出ています。
これがポインタの見た目です。
ではこの箱を実際に使ってみましょう。
最初に箱のスイッチはOFFにしておきます。
この状態はポインタがOFFの状態です。
そして、箱の中にアドレス(モノの場所)が書かれた紙を入れます。
それから箱のスイッチをONにします。
すると、尻尾の矢印がピーンと伸びて、紙に書かれたアドレスの場所を指し示すようになります。
この状態がポインタがONの状態です。
この状態であなたが箱に100円を入れると、その100円は矢印の示した場所にワープします。
箱のスイッチを切ってOFFにすると、尻尾の矢印はまた縮んで元に戻ります。
しかしさっきの100円はさっきの場所に置かれたままです。
次に箱に別のアドレスが書かれた紙を入れます。
そしてスイッチをONにすると再び尻尾の矢印が伸びて、そのアドレスの場所を指し示します。
その状態で箱に500円を入れると、さっきと同じように矢印の伸びている先に500円玉がワープします。
以上がポインタの機能の全てです。
小さな箱とはポインタ変数のこと
先ほどの解説の「小さな箱」とはポインタ変数のことです。
ポインタ変数はさっきの解説のように、2つの状態を持っています。
それはスイッチがONの状態と、スイッチがOFFの状態です。
スイッチとはアスタリスクのこと
先ほどの解説の「箱についてるスイッチ」とはポインタ変数に付けられるアスタリスク(*
)のことです。
このアスタリスクを付けた状態がONの状態で、付けていない状態がOFFの状態です。
つまりvar
というポインタ変数があったとすると、↓の状態がOFFで
var
↓の状態がONになります。
*var
アドレスはメモリ上の番地のこと
先ほどの解説で出てきた「アドレスの書かれた紙」というのは、コンピューターのメモリ上のアドレスを指し示す値のことです。
これはアドレス値と呼ばれ、このアドレス値がわかればメモリ上のオブジェクトの位置がわかります。
OFFの状態のポインタ変数にはアドレス値を代入することができます。
var
というポインタ変数があったとして、そのポインタ変数にアドレスを代入する場合は↓のようになります。
var = 12345;
↑のアドレス値は解説用の適当なものです。コンパイラに通した場合はエラーになる可能性があるのでご了承ください。
箱に100円玉を入れるということ
先ほどの解説では箱に100円玉を入れると、その100円玉が矢印の指し示す場所にワープしました。
ポインタ変数のスイッチがONになると、ポインタ変数についている目に見えない矢印が、パソコンのメモリまで伸びていきます。
そしてその矢印が伸びた状態で、ポインタ変数になにか値を代入すると、メモリの先のオブジェクトの値が変わるわけです。
つまりvar
というポインタ変数があって、そのポインタ変数に別の変数foo
のアドレス値を入れたとします。
var = &foo; // fooのアドレス値をvarに代入
この状態でvar
にアスタリスクを付けてスイッチをオンして、別の値を代入すると、
*var = 123; // スイッチをONにした状態で123を代入する
結果的にfoo
の値が変更されるということになります。
これはvar
の中に入れているアドレス値がfoo
変数のアドレス値だからです。
ONの状態のvar
からは尻尾の矢印がfoo
変数のところに伸びています(メモリ上の)。
ポインタを使うとこのように異なるオブジェクトの値を間接的に変更することができます。
変数のアドレス値の参照
変数のアドレス値を参照するには、先ほどの例のように変数の頭に&
をつけます。
var = &foo;
↑の例だとポインタ変数var
にはfoo
変数のアドレスが入ります。
つまりvar
という小さな箱の中にfoo
のアドレスが書かれた紙が入るということになります。
ポインタ変数の宣言
C/C++は変数に型があるプログラミング言語です。
そのためポインタ変数にも型があります。
たとえばint
は整数を表現する型です。
int
型のポインタ変数を宣言するには↓のようにします。
int *var;
↑のコードを見るとアスタリスクが付いてるからスイッチがONになっているように見えます。
しかし実際はスイッチはOFFの状態です。
ここがポインタの混乱する所なのですが、ポインタ変数の宣言に関してはスイッチは常にOFFだと思うようにしてください。
↑のコードのアスタリスクは「これはポインタ変数ですよ」という記号みたいなものです。
宣言の場合、ポインタ変数はOFFの状態なのでアドレス値を宣言と同時に入れることができます。
たとえば↓のようにです。
int *var = &foo;
NULLポインタ
NULL
ポインタとは今回の例ではいわゆる「0が書かれた紙」のことです。
アドレスは0
, つまりどこも指し示していないということになります。
このアドレスが箱の中に入れられると、尻尾の矢印はどこにも伸びません。
しかしスイッチをONにして100円玉を入れようとすることはできます。
もちろんアドレスが0
なので100円玉はどこにもワープさせられません。そのためエラーになります。
このエラーはJavaなどの言語ではNull Pointer Exception
などと呼ばれることがあります。
NULL
ポインタはC言語ではNULL
というマクロで参照することができます。
int *var = NULL;
NULL
ポインタは(void *)0
で定義されることが多いですが、これは処理系依存です。
アドレス値の出力
printf()
関数の%p
指定子を使うとアドレス値を視覚的にわかりやすく出力することができます。
printf("%p\n", NULL);
おわりに
ポインタは慣れると扱いやすいものですが、その概念は最初は取っつきにくいものです。
しかし今回の箱のイメージを持つことで理解が進むかもしれません。
🦝 < ポインタは友達