前回でコンピュータ内のメモリの概念を説明しました。そして最後にポインタとは変数の場所をプログラマが意識する仕組みとも。そこで今回はその文法について説明していきます。文法解説なので今回だけでポインタを理解する必要はなく、また、わからなくても当然ですので、まずはこんなふうに使うのかと、なるほどと思うだけで十分です。
--
いきなりここに飛んで来ちゃった人は、よろしければ下記からご覧ください。


ポインタの型
ポインタは変数の場所を意識します。つまり変数のアドレスを扱います。故に変数の型に応じた位置を示す必要があります。※後述 そのため、ポインタ専用の型は存在しません。それぞれの変数の型指定に *(アスタリスク)を付与するとポインタとなります。例えば

int* ptr;

このように記述することで ptr は int 型の位置を示すポインタを格納する変数として宣言されます。この ptr の事をポインタ変数と呼びます。ちなみに、C言語の教科書などでは

int *ptr;

このような書き方を推奨していますが、本ブログでは int* という書き方を推奨します。これは私独自らしいので、気に入らなければ C言語教科書推奨で構いません。私が int* と書くのは int* で型全体と考えているためです。

アスタリスクを付与すればだいたいはポインタ変数になります。それは構造体でも例外ではなく、例えば…

struc TPoint { int X; int Y; }; typedef struct TPoint Point;
このような構造体でも

Point* pLocate;

アスタリスクを付けることで、構造体変数のアドレス(場所)を格納できるようになります。


  • 変数のアドレス
入れ物であるポインタ変数が用意できたところで、今度はそこにアドレスを入れます。ここで重要なのは、型が違う場合はアドレスを格納することは出来ないという点です。int 型のポインタ変数に、char 型の変数のアドレスを入れてはいけません。無理やり格納することは出来てしまうのですが、それがC言語の素晴らしいところでもあり、ダメなところでもあるのですが、保守性を考えるととてもじゃないですが推奨できません。

横道に逸れました。変数名に &(アンパサンド)を付与すると、変数のアドレスとなります。ここでアレと思ったヒトはご明察。そう、scanf_s の時にこのように説明しました。
この & を付与する事で、変数がメモリ内のどこにあるのかという
位置(アドレス)を指定する事になります。
そう、コレ実はポインタだったんですね。scanf はキーボードからの入力を変数に格納します。その際、その変数がどこのアドレスにあるのかを知る必要がありました。そこでアンパサンドを付与した指定だったんです。

int num; と宣言した変数 num のアドレスを、先に説明した int* ptr; にアドレスを入れるには…

int num; int* ptr; ptr = #

※ 通常版ならまだ通常のお値段で予約できますが、コレクターズは予約の段階で転売価格とか頭おかしい…
これで ptr には変数 num のアドレスが格納されます。さて、これは慣れるしかないのですが、配列のアドレスは少しだけ事情が異なっています。内藤の解釈(それが正しいかどうかはさておき)では、配列はポインタアクセスを簡略化した仕組みであると考えています。そのため、

int array[10];

この array 配列の場合は、int 型の変数が 10個連続にメモリに配置された状態で、その先頭アドレスが array と定義されていると考えています。つまり array という配列名が既にアドレスなのです。そのため、配列名に関してはアンパサンドを付与する必要はなく、いきなり

int* ptr = array;

このように記述することが可能となっています。


  • ポインタから操作する
ポインタはアドレスを示していると何度も説明してきました。そして、そのアドレスに格納されている変数の値を取り出したり書き換えたりすることが出来ます。まずは取り出す例です。num に格納された値を ptr から取り出してみます。

int num = 1234; int* ptr = # printf("value = %d\n", *ptr);

ポインタ変数の先頭にアスタリスクを付与することで、そのアドレスの中身に対してアクセスするという意味になります。そのため、この printf では ptr で示されたアドレスに格納されている値が取り出されたというわけです。

ポインタ変数宣言でも、中身に対するアクセスも、どちらもアスタリスクを使うため少し混乱しますよね。私はポインタが難しいと言われる理由に一つに、ポインタではなんでもかんでもアスタリスクとアンパサンドの記号に意味を持たせたためではないかと思っています。残念ながらこればっかりは覚えるしかないので…
  1. 変数宣言時のアスタリスクはポインタ変数宣言
  2. ポインタ変数の接頭語としてアスタリスクがあれば値を使う
このように理解しておいてください。ポインタ変数を経由して値を入れる場合は、接頭語にアスタリスクを付けた状態で、値を代入すれば良いです。

int num = 1234; int* ptr = # *ptr = 9801; printf("value = %d\n", num);

これで3行目で num の値は 9801 に置き換わり、printf の表示結果は 9801 となります。

以上がポインタの文法的な基礎となります。この説明だけではわかったけどわからないと思うんです。理由はたぶん皆さん最初に感じるだからなに?という印象なのかなと。そのため、一番最初に今回は、なるほど、ふーん、と感じるだけで十分ですと説明したのです。次回からポインタを使って何が出来るのかを説明していきます。その使い方を理解していく過程で「だからなに?」がなるほど便利だ!に変わっていくことを期待しています。

ということで、しばらくポインタの話は続きます。よろしくお願いします。
※ コントローラに 5,000円出すなら私はこちらを買います!