ポインタを学ぶ(3) ポインタの用途
ポインタの実際の用途について考える。
とはいっても、主なのはこの3つくらいだろう。
関数から関数外の値を操作する
この用途でもっともよく知られているのは、swap関数の実装だ。
swap関数とは、2つの同じ型の引数を取り、その2つを交換する関数である。
(C++では<algorithm>
(C++11からは<utility>
)にテンプレート関数として用意されている)
今、int型引数のswap関数を実装したい。
ポインタを知らなければ次のように書こうとするだろう。
void swap(int a, int b){ // 間違った例 int c = a; a = b; b = c; }
この処理は、関数に固めないでmainにべた打ちする、とかならちゃんと動作する。
でも、関数にしてしまうとうまく動かない。
なぜなら、C/C++では(C++の参照を除いて)すべての引数は値渡しされるので、関数内で扱う引数は、与えられた引数のコピーに過ぎないからだ。
そこでポインタの登場だ。ポインタを使った正しい実装は次のようになる。
void swap(int* a, int* b){ // 正しい例 int c = *a; *a = *b; *b = c; }
引数でポインタを取るようになっている。これで引数の(コピーでない)実体にアクセスして変更することができる。
この関数を使うには、たとえばx
,y
を交換したいなら、swap(&x,&y)
とすればいい。
ファイル操作をする時に、FILE型のポインタが必要なのも、これと同じ理由と推測できる。
構造体も値渡し(コピー)だから、操作にはポインタが必要なはずだ。
メモリ動的確保
ポインタがもっとも必要とされる場所と言えるだろう。
メモリ動的確保とは、言ってしまえば適当な要素数の配列を実行中に確保すること、と言えるだろう。
動的確保が普通の配列とどう違うかと言うと、要素数を実行中に決められることだ。
具体的なやり方は、ここには書かないことにしたい。
無駄な領域を使わないようにする
巨大な変数を引数としてとる関数を考える。
普通の値渡しで書くと、関数が実行される際には実引数がコピーされて、関数内で用いられる。
そうなると、同じデータが2つメモリ上にあることになり、無駄である。特に大きいものがコピーされる場合は。
そんなときに、ポインタを使う。
ポインタの大きさは、メモリアドレスの大きさ(32bitとか64bitがせいぜい)で、ほとんどの巨大な変数よりも小さい。
勉強不足がいよいよ誤魔化せないレベルになってきた。
2015/3/22 領域を節約する用途を追記(一応書いておいたほうがいい気がしたので)