コンパイラ
上の関数の最後の再帰呼び出しに末尾呼び出しの最適化を行うと、どのような効果があるか。
int fact(int n, int acc) {
if (n <= 1) return acc;
return fact(n - 1, acc * n);
}
- A再帰の回数が半分になり、計算の結果も2倍速く求まる
- B関数がインライン展開され、再帰そのものが定数に置き換わる
- C呼び出しが分岐(ジャンプ)に置き換わり、再帰が深くてもスタックが増えない
答えと解説を見る
正解:C. 呼び出しが分岐(ジャンプ)に置き換わり、再帰が深くてもスタックが増えない
この関数の再帰呼び出しは、関数の最後の処理で、その結果をそのまま返しています(末尾呼び出し)。呼び出しのあとに残る処理がないので、今の関数のスタックフレームを使い回し、引数を書き換えて関数の先頭へジャンプする形に変換できます。これによりループと同じ働きになり、再帰がどれだけ深くてもスタックが増えず、あふれる心配がなくなります。再帰の回数は変わらず、nが実行時に決まるので定数にはできません。
- A. 繰り返しの回数は変わりません。
- B. nは実行時に決まるので、定数には置き換えられません。
- C. 正しい。ジャンプに置き換わり、スタックが増えなくなります。