#pragma twice

KAB-studio > プログラミング > #pragma twice > 064 Version 4.14 引数に使うポインタ、そして参照

#pragma twice 064 Version 4.14 引数に使うポインタ、そして参照

前のページへ 表紙・目次へ 次のページへ

 Version 4.14
引数に使うポインタ、そして参照

前にも言ったけど、C++ には〈ある目的のために機能が用意されている〉
ことが結構あります
 const の時に言ったのだよね
そう。ポインタにもそういう部分があります。たとえばこんな関数

int RetOneValue()
{
    return 100;
}

これって、ただ 100 を返すだけじゃん
そ。さて、この関数を〈 100 と 200 のふたつの数字を返す関数〉に改造
したい場合、どうする?
……

    return 100, 200;

とかは?
うお、すごいこと考えるね。で、受け取る方は?
……

void CallRetOneValue()
{
    int i1, i2 = RetOneValue();
    TRACE( "%d\n", i1, i2 );
}

あ”、ビルドしたら警告……

warning C4700: 
 値が割り当てられていないローカルな変数 'i1' に対して
 参照が行われました。

結果は……

-858993460, 200

……ようするにダメってことでしょ!! ね、そうでしょ!!
まあ落ち着いて。実際ダメなんだけどさ
あうう
 return だけを使った場合、値はひとつしか返せないから。だから、値を
ふたつ以上返すために別の方法を使います
もしかして、ポインタを使うの?
そゆこと

void RetOneValueToPointer( int *p_piRet )
{
    *p_piRet = 100;
}

// 下の関数を呼んでください。
void CallRetOneValueToPointer()
{
    int i;
    RetOneValueToPointer( &i );
    TRACE( "%d\n", i );
}

??
まず下の関数から。変数 i を作ってるね
うん作ってる。次の行で上の関数を呼んでるけど、そんときにその変数の
アドレス渡してるね
そう、で、上の関数へ。このとき、さっきの変数はまだなくなってないっ
てことに注意してね
そっか、ローカル変数は〈関数の最後に行ったら消える〉んだもんね
他の関数に行ってもまだなくならないから。で、この変数のアドレスがポ
インタに入ってるから
 * をポインタに付けると、アドレスが指す変数、つまり i と同じになる
……つまり、こうやると他の関数の変数に数字入れられるんだ!
そういうこと。 p_piRet の中のアドレスを通して、外の関数の変数 i に
アクセスしてるってこと
はー
こうすることで〈引数を経由して値を返す〉ことができます
ひきすーってなんだっけ
う”、関数の小カッコの中の変数のこと
あ、 p_piRet のことね
で、 RetOneValueToPointer() から返ってきた時にはもう i の中に 100 
が入ってるから
それを表示して 100 、ってことなんだ
で、引数はひとつじゃなくふたつでもみっつでもいいから、こうすればふ
たつ以上の値を返すことができます

void RetTwoValueToPointer( int *p_piRet1, int *p_piRet2 )
{
    *p_piRet1 = 100;
    *p_piRet2 = 200;
}

// 下の関数を呼んでください。
void CallRetTwoValueToPointer()
{
    int i1, i2;
    RetTwoValueToPointer( &i1, &i2 );
    TRACE( "%d, %d\n", i1, i2 );
    // 100, 200
}

あ、こーゆーふーに変数を増やしてくだけでいいんだね
そ、簡単でしょ
なんとなく
なんとなく?
んー、アドレスとかポインタとかってさ、メモリ見て、あーやってこまご
まとした操作したじゃない
うん
それに比べると、なんかこーゆー使い方ってシンプルすぎてなんかなーと

それはあるね。実際にはアドレス渡してそれ通して操作してる、ってこと
なんだけど、それよりも分かりやすいから
単に値返すためだけの道具、みたいな感じ? なんかポインタっぽくない
かも
これは〈目的のための機能〉の逆かもね。まずアドレスを操作できるって
いう機能があって、それが
引数から値を返せるってゆー目的にも使えちゃう。頭では理解できるんだ
けどね
じゃ、ポインタを使わない方法を教えようか
ポインタを使わない?
参照って憶えてる?
んっと、Ver 3.22 ( No.047 )でやったのだよね
そこ、思い出しながら読み返してみて
はーい。んっと、 theApp って変数を使いたくて、でもこの変数のコピー
は作れないから、 theApp の代わりになる〈参照〉ってものを作って……
ん?
そ、ポインタに似てるでしょ
うん、なんで?
それは、火美ちゃんみたいな人がいるから

ま、まずは使用例から見た方がいいかな

void UseReference()
{
    int i = 100;
    int &ri = i;    // これが参照。
    TRACE( "%d, %d\n", i, ri );   // 100, 100

    ri = 200;
    TRACE( "%d, %d\n", i, ri );   // 200, 200
}

あ、ポインタの時に似てる!
2行目で作ってる ri って変数、これが参照
ポインタの時は * で、参照の時は & なんだ。あれ? i なの? &i じゃ
ないの?
そこが参照のミソ。参照はアドレスを格納するの〈じゃない〉から、アド
レスを渡す必要はないわけ
??
ポインタは〈アドレスを格納する〉ことで、間接的に〈他の変数の代わり〉
になることができたでしょ
 ATM とカード番号みたいなもんだよね
参照は直接的に〈他の変数の代わり〉になることができるわけ。つまり〈ア
ドレス〉って考えがないわけ
つまり、ポインタの〈他の変数の代わり〉って機能だけを抜き出したのが
参照ってことなんだ
そういうこと。だから、参照は何もせずに〈参照する変数〉として振る舞
います
だから * 付けないで i の値が取れたり変えれたりするんだ
そこで、さっきの〈ふたつ値を返す関数〉を参照でしてみると

void RetTwoValueToReference( int &p_riRet1, int &p_riRet2 )
{
    p_riRet1 = 100;
    p_riRet2 = 200;
}

// 下の関数を呼んでください。
void CallRetTwoValueToReference()
{
    int i1, i2;
    RetTwoValueToReference( i1, i2 );
    TRACE( "%d, %d\n", i1, i2 );
    // 100, 200
}

って感じになります
 * がなくてすっきりしたね。でも……
でも?
なんかしっくりこないかなー
うん、どの辺がそうなのかは分かるけど、それは次回に取っておきましょ
う。今回最後は、もうちょっと参照について。参照のアドレスを取得するに
は?
ポインタの時と同じで、 & 付ければいいんじゃないの?
というわけでこの関数

void ShowRefAddress()
{
    int i = 100;
    TRACE( "%X\n", &i );  // 64F530
    int &ri = i;            // ここにブレークポイント。
    TRACE( "%X\n", &ri ); // 64F530
}

最初はブレークポイントをセットせずに実行してみて
ほいっ。あ、 i と ri のアドレスが一緒! って、つまりこーゆー部分
も i になりきってるってこと?
そういうこと。参照のアドレスは取得できないんだよね。取得しようとす
ると参照先のアドレスが返ってきちゃう
ってことはさー、参照ってメモリの上にないの?
そういうわけじゃないんだよね。というわけで
ブレークポイントセット、止めて、メモリを見る!
あ、前後1行ずつ見てみて

0064F51C  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC
0064F530  64 00 00 00 8C F5 64 00 E2 3E 40 00 2C F8 64 00 C0 01 52 00
0064F544  F0 F8 64 00 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC

 i が 0064F530 にあって、 100 が入ってるから 64 00 00 00 、うんい
つもどおりだね
じゃ、1行進めて

0064F51C  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC 30 F5 64 00
0064F530  64 00 00 00 8C F5 64 00 E2 3E 40 00 2C F8 64 00 C0 01 52 00
0064F544  F0 F8 64 00 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC

あ、右上の部分変わった!! えっと CC CC CC CC から 30 F5 64 00 に
……って、これって 0064F530 だよね
そ、 i のアドレス。つまり ri がここにあるってこと、そして参照の中
にも結局アドレスが入ってるってこと
なーんだ、結局参照もポインタと同じなんだ
そういうこと。その辺を含みつつ、次回、ポインタ編最終回に続く!!

/*
    Preview Next Story!
*/
で、最終回の後は?
気が早いねー。またウィンドウズっぽいプログラムに戻るけどね
なんかちょっとホッとするかも
ふっふっふー、それはどうかな
げげ
というわけで次回
< Version 4.15 const 再び >
につづく!
ああ、火美ちゃんの阿鼻叫喚が聞こえるようだ……
ってあんたが言わせるんでしょーが
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。