[過去ログ] 【初心者歓迎】C/C++室 Ver.100【環境依存OK】 [無断転載禁止]©2ch.net (1002レス)
前次1-
抽出解除 必死チェッカー(本家) (べ) 自ID レス栞 あぼーん

このスレッドは過去ログ倉庫に格納されています。
次スレ検索 歴削→次スレ 栞削→次スレ 過去ログメニュー
34
(3): デフォルトの名無しさん [sage] 2016/11/10(木) 10:52:07.29 ID:8ULjF/bN(1/8) AAS
独習C第4版 P197ページの再帰のプログラムなのですが、
#include <stdio.h>

void recurse(int i);

int main(void)
{
recurse(0);

return 0;
}

void recurse(int i)
{
if(i < 10) {
recurse(i + 1);
printf("%d " , i);
}
}

実行結果は
9 8 7 6 5 4 3 2 1 0

の動作がわかりません。10になるまでprintfが実行されずに+1され続けるのはいいのですが、
なぜ10になったらiが戻り始めるのでしょうか?
あまりに初心者な質問ですみません。
36
(1): 34 [sage] 2016/11/10(木) 11:07:42.28 ID:8ULjF/bN(2/8) AAS
>>35
35(2): デフォルトの名無しさん [sage] 2016/11/10(木) 11:03:28.04 ID:6ImFpJhK(1/3) AAS
引数だけ書くと
0+1
1+1
・・・
9+1
ここまではprintfまで来ないまま再帰
9+1でifに入らないからrecurseからリターン
printfがiを表示(9)してリターン
printfがiを表示(8)してリターン
の繰り返し
早速のレスありがとうございます。

>9+1でifに入らないからrecurseからリターン
ということはmain関数のreturn 0でプログラムは終了してしまうのではないですか?
なぜprintfが呼ばれるのかわからんのですが。(iが減算される理由もわかりません)
37
(2): 34 [sage] 2016/11/10(木) 11:12:33.48 ID:8ULjF/bN(3/8) AAS
if(i < 10) {
recurse(i + 1);
printf("%d " , i);
}

recurseとprintfは同じifブロックに入っているので、ifが偽なら両方共スキップされると思うのですが、
なぜprintfだけ呼ばれるのでしょうか?
40
(2): 34 [sage] 2016/11/10(木) 11:40:24.95 ID:8ULjF/bN(4/8) AAS
>>35-39さん
どうも再帰関数とforループがごっちゃになっていたようです。
何となくわかりました。
後は自分で考えてみます。
どうもありがとうございました。
43
(3): 40 [sage] 2016/11/10(木) 14:01:09.75 ID:8ULjF/bN(5/8) AAS
>>41
41(1): デフォルトの名無しさん [sage] 2016/11/10(木) 12:42:30.91 ID:69ogPHI/(2/4) AAS
再帰呼び出し後に書く  recurse(i+1); printf("%d ", i);

書いてから再帰呼び出し printf("%d ", i); recurse(i+1);
の違いとか

呼び出しの出入りを整理する
printf("in:%d\n", i);
recurse(i+1);
printf("out:%d\n", i);
と見えてくると思うよ
>再帰呼び出し後に書く  recurse(i+1); printf("%d ", i);
>と
>書いてから再帰呼び出し printf("%d ", i); recurse(i+1);
>の違いとか

これはこの本の次のページにも書いてありました。
書いてから再帰呼び出しの場合は昇順(1,2,3,4,5,6~)になりますね。

相変わらず曖昧な理解なんですが、
どのiの場合もi=10に達するまではrecurse(i+9)までしか実行されていなくて、
printfは実行されていない待機中の状態だと考えればいいのでしょうか?
それでi=10でif条件文を抜けて、i=9からi=0まで数字が大きい方から順番にまだ実行していなかった
printfを降順で実行していくのでしょうか?

この本(独習C)には
> 引数の値が10に達すると、recurse()の再帰呼び出しから戻りはじめます。関数は、呼び出し元に戻る
>ものなので、recurse()は直前の呼び出し元に戻り、そこでprinf()を文を実行して「9」と表示し、
>さらに前の呼び出し元に戻ります。こうしてrecurse()は、今度は「8」と表示します。 その後も同じ>プロセスが繰り返され、すべての呼び出しから戻った段階でプログラムが終了します。

実行される順番が、最初のi=0からではなく、直近のi=9からなのはなぜなのでしょうか?
50: 40 [sage] 2016/11/10(木) 14:33:22.38 ID:8ULjF/bN(6/8) AAS
スタックフレームで検索して見たところ、
外部リンク[html]:brain.cc.kogakuin.ac.jp
このページが一番わかりやすそうです。
LIFOなんで新しい関数と引数が上の方に積み上がっていくと考えれば良いのでしょうか?
first outなんで実効は新しい順(つまり今回の例の場合はi=9)ということですね。

スタックフレームという言葉で検索したらおもしろそうなサイトがたくさん出てきました。
皆さん今回はありがとうございました。
52
(1): 43 [sage] 2016/11/10(木) 15:05:17.38 ID:8ULjF/bN(7/8) AAS
>>51
51(1): デフォルトの名無しさん [sage] 2016/11/10(木) 14:51:19.03 ID:IzCfpVGN(1) AAS
>>43
まず大前提としてプログラムの流れは1本道で別れたりしないし、待機みたいなことも普通しない

そして再帰関数という特別な関数があるわけではない、recurseは普通の関数と何も変わらない

void recurse(int i)
{
if(i < 10) {
recurse(i + 1);
printf("%d " , i);
}
}

この4行目はrecurseという関数を呼び出している
つまり自分自身を呼ぶのでこの4行目の呼び出し後、recurse関数の最初に戻る
ただし引数iは1大きい値で呼ぶ
これを入れ子のように10回繰り返すことになる
レスありがとうございます。
外部リンク:ipa-zone.info
このページに私が使っている独習Cの再帰の部分が丸ごと転載されているんですが(違法?)、

i=0~10と昇順で増加していく前半部分でも呼び出された関数(recurse(1)など)は終了した訳ではないですよね?
後半のi=10から降順で減少していくときにはじめてprintfが実行されて関数が終了すると思うんですが、
LIFOなんで最後に呼び出されたrecurse(9)からrecurese(0)まで降順で残ったprintfを実行していくということではないんですか?
56: 52 [sage] 2016/11/10(木) 15:39:54.19 ID:8ULjF/bN(8/8) AAS
>>53
53(1): デフォルトの名無しさん [sage] 2016/11/10(木) 15:15:27.68 ID:gEXUDT4B(5/5) AAS
>実行は新しい順(つまり今回の例の場合はi=9)ということですね。

難しく考える必要は無い
関数を呼び出すとき、自分が今何をしていたかをそっくりそのまま保存した状態で
新たにスタックを確保して、呼び出した関数を実行する
関数の実行が終わると、使っていたスタックを開放して
呼び出される前に実行していた処理に復帰する
ちょうど君が
1)ビデオを見ていた時に電話がかかってきたら、ビデオを一時停止して電話に出る
2)電話が終わると、ビデオを再生して続きを見る
のと同じで、ビデオの一時停止機能がスタックに相当している
で、君がこの日のことを日記を書くとき
1)のことを重視すれば、ビデオ→電話、って順になるし
2)のことを重視すれば、電話→ビデオ、って順になる
実際にはビデオ→電話→ビデオ、という順で物事は流れているんだが
どこのタイミングを切り取ってくるかで順番が変わるのだ
下から順番に1,2,3,4,5と積み上げて、上から順番に5,4,3,2,1と取り出すとき
積み上げるとき(積み上げる前)に出力すると1,2,3,4,5だし
取り出すとき(取り出した後)に出力すると5,4,3,2,1になる
実際には1,2,3,4,5,4,3,2,1という順で処理は走っているが(積み上げる→取り出す)
前半に着目すれば1,2,3,4,5だし、後半に着目すれば5,4,3,2,1なのだ
レスありがとうございます。参考になりました。
前次1-
スレ情報 赤レス抽出 画像レス抽出 歴の未読スレ AAサムネイル

ぬこの手 ぬこTOP 1.417s*