「分かっていない」というぼやき - わさっきの答えを書いてみることにしました.昨日取り上げた『ベストプロフェッサー』の影響も受けています.
会話文ですので,無駄に長いです.
値渡しと参照渡しの違いを理解するには,「それぞれ何をする(渡す)ことか」と「それぞれの渡し方で,関数などでの処理中,あるいは処理後にどのような違いがあるか」の2点を押さえる必要があると考えます.本日のエントリは前者のみです.
会話はフィクションですし,私自身は,このような形態で救済(単位認定)をしたことはありません.
学生が来た
(こん,こん)
先生「はいどうぞ」
学生「昨日メールした,○○です」
「はい待ってました.えっと,今年度卒業の予定で,それで,私の科目の点数が気になるのですね」
「そうです」
「んで合否ですが…このままだと,合格は出せませんね」
「はあ」
「レポートを出していないのが痛い.試験はまあまあだけど,残念ながら,60点には届いてません」
「それで,救済していただけると」
「救済という言葉は好きでないけど…まあ,レポートに替えて,私の科目の内容に関する重要なところを理解して,答案という形に表せたら,よしとしましょう」
「お願いします」
「今日の面談の前に,勉強してきました?」
「はい,レポート課題と,試験問題は見直してきました」
「ふむ.それぞれ解答例を出しているけど,それも見た?」
「はい」
「了解.レポート課題の答えを公開してなかったら,解いてもらいたいところだけど,そうもいかないので,新たな課題を出しますね」
「お願いします」
「今から,『値渡しと参照渡しの違い』について,2人でディスカッションしましょう.そしてその内容を整理して,レポートとして提出してください」
「…わかりました.『値渡しと参照渡しの違い』のレポートですね」
「あっとその考え方は,半分当たりで半分外れだからね.『値渡しと参照渡しの違い』を自分なりに調べてレポートにするんじゃあない.それだったら,悪いが,本やWebの情報の引き写しで終わってしまうので」
「えっ…」
「今から,値渡しと参照渡しの違いを,対話しながら確認していくんですよ」
「…何か難しそうですが,わかりました」
「じゃあ始めるね.そうそう,そこで,あなたが最初にすることは,何だと思いますか?」
「えっと…値渡しと参照渡しが何か,言うことですか?」
「いや.最初に,筆記用具を出してください.重要なことをメモしないと」
「あ,はい」
値渡しと参照渡しを比較する前に
先生「では,うん,あなたの思う通りでいいので,値渡しとは何か,参照渡しとは何か,説明してみてくれますか」
学生「はい……」
「どしたの?」
「ちょっと,緊張してしまって.自分の書いたメモを見ていいですか?」
「うーん,書いたメモを持ってきてるのね.いいと言いたいけど,条件をつけましょう.メモを見るのはかまいませんが,発言するときは,そのメモを見ないでください」
「…えっと,やってみます.…思い出せました」
「はいじゃあメモは伏せて,言ってみてください」
「値渡しは,関数の受け渡しで値を渡すものです」
「へえ」
「ダメですか?」
「ああ失礼.もう一度言いながら,記録用のノートに書いておいてください」
「はい.値渡しは,関数の,受け渡しで,値を,渡す,もの,です」
「最後の『ものです』はいらないね,記録をとるときは」
「えっと,はい」
「消しゴムは使わない.横線引きましょう」
「はい」
「次に,参照渡しを説明してくれますか.まずはノートに書かずに」
「えっと…関数の受け渡しでアドレスを渡すものです」
「ん.じゃあ復唱しながら,書きましょう」
「関数の,受け渡しで,アドレスを,渡す」
「んで言ってくれた内容について僕の思うところを言うと,手短なメモとしてはいいのですが,値渡しと参照渡しの『説明』としては不十分です」
「…はあ」
「まず,『関数の受け渡し』のところが不適切です」
「…」
「戻り値についても扱うんですか?」
「あ! いえ,それは」
「じゃあ,『関数の受け渡し』のところは,何と言えばいいかな?」
「えっと…『関数の引数』,ですか」
「うん,焦点に近づいているね.でもまだ安心できないよ.関数で『引数』って言葉を出すときには,2種類あるんですよね」
「はい,仮引数と実引数です」
「それぞれ何ですか?」
「関数の引数に書くのが仮引数で…」
「いや,ダメダメ」
「まずいですか?」
「『関数の引数』って何かね?」
「えっと…関数を定義するときに,カッコ内に書く変数です」
「うん,そのほうがいい.さて実引数は?」
「関数を呼び出す側で書く変数です」
「うむ,ここでやっと『呼び出す』が出てきたね.値渡しと参照渡しの『違い』を説明する前に,それぞれの共通点というか,対象というか,何に関しての『違い』を説明していくのかを,明らかにしておかないといけないんですよ.ここでは『関数の呼び出し』ですね」
「あ…はい」
「仮引数と実引数がそれぞれ何かというのは,ノートにとっておきましょう」
「はい」
「んでとったあとで申し訳ないけど,実引数のところで『変数』と言ったところ,そこは横線を引いて,そばに『値』と書いてください」
「え?」
「実引数は,変数に限らないでしょ?」
「…あ,はいそうです,わかりました」
値渡しとは
先生「関数の呼び出し,仮引数,実引数という重要な言葉を引っ張りだしたところで,では,これらを使って,値渡しの定義をし直してください.持ってきたメモは見ないように」
学生「今書いたのは,見ていいですか?」
「うん,いいですよ」
「えっと…関数の呼び出しで,実引数の値を仮引数に渡すということです」
「いいと言いたいけど,もうひと押ししましょう.『渡す』とは,具体的に,何をすることですか?」
「渡す…?」
「少しヒント.実引数が変数であれ値であれ,仮引数という変数とは異なるものですね?」
「はい」
「異なるところに『渡す』とは? メモリを考えてくれるといいんだけど」
「あ! メモリ上でコピーすることです」
「うん,『コピー』が重要!」
「(笑)」
「おかしいこと言ったか? まいいや,もう一度,ノートの上で整理して,定義を読んでくれますか?」
「はい…値渡しとは,関数の呼び出しの際,実引数の値そのものを仮引数となる変数にコピーすることです」
「お,『〜の際』とか『そのもの』とか,洗練された表現を取り入れていますね」
「いえ,あの,『そのもの』は,勉強していて見かけたんです」
「うん,参照渡しと対比するときに有用な修飾語ですね」
参照渡しとは
先生「では次に参照渡しの定義,これも修正版を作って,言ってみてください」
学生「えっと…参照渡しとは,関数の呼び出しの際,実引数の値そのものではなく,そのアドレスを仮引数にコピーすることです」
「さて…」
「まずいですか?」
「うん,あまりよくない.まず,そうだな,ここでの参照渡しを,C言語に限定して考えますか? それとも,プログラミング一般で考えますか?」
「まあ,Cの科目ですので,Cで」
「ではそうしましょう.そうすると,仮引数はどんな変数ですか?」
「…ポインタです」
「うん,参照渡しの説明に,ポインタが出てもらわないと困るね」
「あ,はい…」
「どこに入れる? ま,定義を言い直してみてください」
「え…参照渡しとは,関数の呼び出しの際,実引数の値そのものではなく,アドレスを渡して,関数ではポインタ変数となる仮引数にコピーすることです」
「長くなったねえ」
「はい」
「定義を2つの文で書いてもいいと思うよ.ここだと…参照渡しとは,関数の呼び出しの際に,実引数の値ではなくアドレスを,仮引数に渡すことです.このとき,仮引数はポインタ変数でなければなりません」
「あの,ここは『コピー』じゃなくて『渡す』なんですか?」
「あ,どっちでもいいよ.メモリを考えると,アドレスのコピーをしているんだけど,そこまでは言わなくてもいいので」
「それを言うとまずいんですか?」
「値渡しと参照渡しの違いからは脱線するけど,Cでは,参照渡しといっても,値渡しなのです」
「はい,先生の授業のスライドも,そう書かれていました」
「Cでは,値渡しでその値をポインタ値…『ポインタ値』ってのも,仕様にない,僕の独自表現ですが,ともあれ…ポインタ値にするってことです.つまり,繰り返しますがC言語限定で,参照渡しは,値渡しに含まれるわけです」
「…」
「だからアドレス…さっき僕が言った『ポインタ値』とほぼ同じ意味ですが…これを『コピー』するか,泥臭いところを抜かして『渡す』,あるいは『受け渡す』と書くことにするかは,まあどちらでもいいのです」
「では,最終的なレポートにするときは,ここは『コピー』でなくてもいいのですか?」
「いいよ.それで次に考えるのは,参照渡しで,どんな値が実引数になるかですね」
「&をつける変数,ですか?」
「うん,それを含むけど,さすがに『&をつける変数』では,説明に使いにくいので,よりよい表現を考えないといけませんね」
「はい,え…」
「あ,すまん.実引数にどんなのがなり得るか,もう一つありますゎな?」
「…配列変数? それと,ポインタ?」
「ああそうだ,ここはポインタと配列変数を分けておくほうがいいですね.じゃあ3つか.それでは,先ほど定義を2つの文に分けましたが,3番目の文として,実引数…というと語弊があるので,呼び出す側は,どんな式でないといけないかを,説明してくれますか?」
「はい…実引数の側は,ポインタか,配列変数名か,&変数のいずれかでなければなりません」
「細かいところだけどここは『のいずれかでなければなりません』はまずいです.&a[0]というのも書けますので.そうだな,『がよく用いられる』にしましょう.では,参照渡しの定義の全体を,整理して,言ってみてください」
「…参照渡しとは,関数の呼び出しの際に,実引数の値ではなくアドレスを,仮引数に渡すことです.このとき,仮引数はポインタ変数でなければなりません.一方,実引数の側は,ポインタ,配列変数名,&つきの変数がよく用いられます」
「よし,これでそれぞれの定義はおしまい.次は効果ですね」
「え,これで終わりじゃないんですか!?」