プログラミングのポインタをわかりやすく解説【C言語】

223, 2021-04-07

目次

ポインタとは?

プログラミングで使われるポインタとはいったいどういうものなのでしょうか?
特にC/C++などの言語ではこのポインタの理解が必須です。

ポインタを知らないとC/C++ではうまいようにプログラムを作ることが出来ません。

結論から言うと、ポインタとは「スイッチの付いた箱」のことです。
スイッチを切り替えることでアクセスするデータを変更することができます。
このスイッチの切り替えの概念が、初心者の人にはうまく理解できないんだと思います。

この記事では、プログラミングのポインタについてわかりやすく解説します。

ポインタの綴りと意味

ポインタはpointerと英語では呼ばれます。
これの意味は「さす人」とか「さし棒」という意味です。
何かを指し示すのがポインタということですね。

ポインタはスイッチの付いた箱

ポインタの概念について解説します。
まず、小さな箱をイメージしてください。

箱の横側にはON/OFFを切り替えるスイッチが付いています。
そして、その箱からは尻尾のような矢印が飛び出ています。
これがポインタの見た目です。

【0223】a.jpg

ではこの箱を実際に使ってみましょう。
最初に箱のスイッチはOFFにしておきます。
この状態はポインタがOFFの状態です。
そして、箱の中にアドレス(モノの場所)が書かれた紙を入れます。

それから箱のスイッチをONにします。
すると、尻尾の矢印がピーンと伸びて、紙に書かれたアドレスの場所を指し示すようになります。
この状態がポインタがONの状態です。

【0223】b.jpg

この状態であなたが箱に100円を入れると、その100円は矢印の示した場所にワープします。

【0223】c.jpg

箱のスイッチを切って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);

おわりに

ポインタは慣れると扱いやすいものですが、その概念は最初は取っつきにくいものです。
しかし今回の箱のイメージを持つことで理解が進むかもしれません。

ポインタは友達