第十回-02 アドレスとポインタ (1)

第九回課題で 2 つの変数の値を交換する機能 (swap 機能) について考え、
関数を用いた swap 機能はこれまでの知識では実現できないことを知った。

今回学ぶポインタを用いることで、関数を用いた swap 機能を実現できる。

swap 機能そのものが重要というではなく、
ある関数から他の関数で宣言された変数を操作するためにはポインタが必要不可欠という点が重要である。


swap 復習

さて、第九回課題で明らかになった問題点を復習しておこう。
main 関数と swap 関数は下図のようにメモリのスタック領域内で別々の領域を用いることになる (下図は概略図)。



main 関数で宣言された変数 x (=10) および y (=20) が swap 関数に渡されるのだが、
この場合、渡されるのは変数の実体ではなく、その値 (10 と 20) であり、
swap 内の変数 x と y は main 関数のもののコピーである。

そして、交換 (swap) されるのはコピーの方であり、main 関数内の x、y はなんら変更を受けないということがわかる。

このように、関数の引数として変数を渡すとき、変数の値が渡されるこの方式のことを 値渡し (call by value) という。

上図のような図を書いてみればわかることだが、これまでの知識では
ある関数 (ここではmain 関数) で宣言された変数を、別の関数 (ここでは swap 関数) から操作することはできない
ということがわかる。

なお、混乱を避けるために一つ復習しておこう。

最初に関数を学んだ際に登場した例は以下のようなものであった。
(第七回-01 関数の基礎のものを、理解を容易にするために少し簡略化した)

double square(double x);

int main(){

  double x = 5;
  double y;

  y = square(x);

  return 0;  
}

double square(double x){

  double val;

  val = x*x;

  return val;
}


このプログラムは、main 関数 で宣言した変数 x (=5) の2乗を square 関数に計算させ、
やはり main 関数で宣言した y に 25 を格納している。

この例の場合は square 関数から帰って来る (return) 戻り値により y を書き換えている。
このように関数から return することで main 関数内の変数を操作する (変数に代入する) ことは可能である。

square 関数の例の場合は戻る値は 1 つだけなのでこのようなことができたが、
swap 関数の場合は x と y の 2 つの変数を操作せねばならないが、 関数には 2 つの値を返す仕組みはないのでそれはできない。
(なお、構造体とかクラスの知識があれば2つ以上の値を返せなくもないが、 この例の場合はそうするのは不自然に思える)

そのようなわけで、以下では「swap 関数から main 関数の変数を操作するにはどうしたらいいか?」という問題を念頭に、
ポインタについて学んで行こう。


ポインタとは何か

ポインタ、あるいはポインタ変数とは、 まずは以下の例を記述、実行してみよう。



このうち、

int *p; // int 型に対するポインタ p を宣言


がポインタ変数 p の宣言である。以下の3点を押えて欲しい。 次に、

p = &x; // ポインタ p に x のアドレスを格納


は、ポインタ p に x のアドレスを格納する、という意味である。
これは、下の模式図で理解すると良いだろう。



メモリアドレスについてこれまで2回勉強してきたので、左の図のような状況 については理解できるであろう。
(ただし、アドレスはここでは説明上の架空のもの)
p というポインタ変数には、x のメモリアドレスが格納されているわけである。

しかし、毎回メモリアドレスを書いて行くのは繁雑であるから、左図と同じことを 右図であらわすとしよう。
つまり、ポインタとはある変数を指す矢印であり、それが p=&x; により変数 x を指すようになる、というわけである。

そして最後、

std::cout << "pの指す値は" << *p << "\n";


上記命令で「*p」という記述が登場しているが、これは 「p が指す変数の値 (ここでは 5)」という意味を表す。

上のように、コンソールに表示することで参照できるが、
下図のように「*p = 10 ;」と記述することで、「 x = 10; 」を実行したのと同じ効果がある。



以上で、ポインタの概略については解説が終った。
ここで、混乱を避ける意味で通常の変数とポインタ変数の使い方の違いを整理しておこう。

宣言 アドレス 備考
通常の変数 int x ; x &x アドレス
ポインタ変数 int *p ; *p p リスクであたい (値)


次に、int 型以外を指すポインタについても例を見ておこう。
以下の例は、double 型の変数を指すポインタ dp の宣言と使用例である。



これも dp = &y; の後には以下のような状況になることを頭に思い描けるようになって欲しい。







←第十回-01 コンソールへの表示に関する補足第十回-03 アドレスとポインタ (2)→

非情報系学生のための C/C++ 入門に戻る