equal_l2’s blog

※記載されている内容の正確性は保証しませんが、間違いを指摘していただければ直します。

ポインタを学ぶ(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 領域を節約する用途を追記(一応書いておいたほうがいい気がしたので)