ポインタについて


ポインタは分かりにくいと考える人は多いと思います.
ある変数があって,何故,アドレスがあるのかイメージがわきにくいのと,
その動作が分かりにくいからではないでしょうか.

変数は変数のまま(値)でいいではないかと言いたくなるのも分かります.

メモリ構造は,0か1を示すbit単位の記憶部が直線的にズラッと並んでいるのですが,単に
0,1,2,3,4,,,と何GB並んでいるビット列に対して,その都度その都度メモリのはじめから
100048333800247番目〜100048333800255番目のbitを指定して,というわけにも行かない
ので,まず8bitで1まとめにして1Byteという単位を用意し,バイト列にデータが並んでいると
いう扱いをすることにしています.

1Byte=8bit=256であるので文字であれば,英文字大小,数字,記号は一通り表現できます.

バイト列の順番に対し,アドレスを割り当てることで8ビット単位のまとまったビット列を扱える
ようにしているのです.
以下のようなメモリの概念図も少し分かりやすくなったのではないでしょうか.

ただし,これは概念上の話であって,メモリ空間のアドレスを扱うには,メモリをコントロール
する必要があるのです.(プログラム上はこのコントロールを意識する必要は特段ない.)

ポインタ変数の宣言

まず,以下のように宣言します.

double val;
double *p;

valは変数であり,値を示しています.さて,気を付けなければならないのはその次の行なのです.
この行ではアドレスであるpをポインタとして宣言するという意味でdouble *pと書かれています.
実はここが紛らわしいのです.
この後プログラムの文中にて,

p

と書かれていれば,ポインタ宣言された*pのアドレスを示します.そして,

*p

と書かれていたら,アドレスであるポインタpの中身,即ち,値を示しているのです.

宣言するときはdouble *pと書かれていて,アドレスであるpを宣言しているのですが,文中では
*pは値であるからややこしいと言えます.実例を示しましょう.
なお,ポインタの表記に際,*と&を見たことがあると思います.

double val;
double *p;

p = &val;

と書いた例を見たと思います.
この文は,変数valのアドレスをポインタ(アドレス)pに渡す,という意味となります.
ですので*pとすればポインタの中身であるvalの値が呼び出せるのです.

しかしながら,

double val;
double *p;

*p = val;

とあれば,値valをポインタpの値*pに代入するという意味となるような気がするのですが,そうでは
ありません.
これですと,まだポインタ(アドレス)の宣言だけしたpは実体を持たず,実体のないポインタの中身
即ち値*pにいきなり変数の値を代入しようともできないのです.紛らわしいのは,

double val;
double *p = &val;

と書いていきなり宣言できてしまうのですが,あたかも*p = &valに見えてしまう点がややこしいのです.

アドレスの共有と双方向性

アドレスと値という概念の分かりにくさはアドレスが同じものを示すため,その値も同じであるという
ことにあると思います.初めに示した,

double val;
double *p;

p = &val;

を考えたとき,まず変数valが設定されます.もちろん&valを使えば変数のあるアドレスを示します.
さて,ポインタpが宣言されたとき,まだ実体はないのです.

ですから,プログラム文中にて,

*p

といきなり書いても,まだ対象が決まっていないので,アドレスも値も分からずエラーが出ます.従って

p = &val;

と書き,変数val(値)の在り処であるアドレス&valを示し,それをポインタ(アドレス)とするという意味で
表記します.=を使っているので混同しやすいですが,代入する,という意味ではないのです.
この表記によって,初めて実体のなかったポインタpと変数valが結び付けられているのです.
すなわち,

val 変数の値 これに値を代入する
&val 変数のアドレス アドレスであるポインタpと同一
p ポインタ 変数のアドレス&valと同一
*p ポインタの値 変数valの値

という関係があります.ですので,具体的な数値は変数valに代入され,そのアドレスは,&valもしくは
pで示され,中身(値)はvalもしくは*pによって呼び出すことができる,という関係があります.
もちろん*pに値を代入すれば,そのままvalの値でもあるのです.

注意すべきことは,上記のポインタと変数のアドレスの記述をしなければ,値*pに直接値を代入する
ことはできないということです.つまり,

*p=1.0;

とすることは,p = &val;の前ではできないのです.
くどいようですが,p = &val;によって以下のような関係が成り立つようになるといえます.

val &val
*p ---
p --- アドレス

もちろん*pは変数のように振舞います.ですので,一定の計算をした後,valを呼び出しても,*pを呼び
出しても中身は同じですから,値は同じとなります.