2

だから私はCで再帰をいじっていましたが、なぜこれが起こっているのかわかりません:
コードA

int foo(int x)
{
 if (x==0) return 0;
 else return foo(--x)+x;
}

int main() { printf("%d\n", foo(10));

コード B

int foo(int x)
{
 if (x==0) return 0;
 else return foo(x--)+x;
}

int main() { printf("%d\n", foo(10));

コード A は 55 ではなく 45 を出力し、私はそれを理解しました。これは、再帰呼び出しが次のように巻き戻されるためです。9+8+7+...+0 = 45

一方、コード B はスタックし、プロンプトに戻りません!! 私はそれをしなければctrl+cなりません。なぜ行き詰まるのですか?10を超えて減少しないためですか?

4

5 に答える 5

9

これは、スニペット B x が再帰呼び出しのにデクリメントされるため、関数は常に foo(10) で呼び出されるためです。

編集:
James McNellis がコメントで指摘したように、 x は関数を呼び出す前にデクリメントされますが、デクリメントされた値の代わりに元の値が呼び出しで使用されます。
基本的に、式 x-- は foo(x--) の前に評価されますが、その値は実際には x であるため、関数は x = 10 で呼び出されます

于 2012-08-21T21:30:26.870 に答える
2

ポストデクリメント(x--)は、関数呼び出しが戻るのを待ってから実行します。したがって、スタックは次のようになります。

foo(10)
foo(10)
foo(10)
...
于 2012-08-21T21:33:26.837 に答える
1

式の値は、格納された値がデクリメントされる前のx--の現在の値です。xそのため、 を呼び出すとfoo(x--)、 への引数の値fooは常に現在の値と同じになり、無限再帰が発生します。


ただし、両方のプログラムの動作は潜在的に未定義であり、 と の部分式の評価順序に依存することに注意してfoo(x--) + xくださいfoo(--x) + x。式を含む最初のプログラムを考えてみましょう

foo(--x) + x

部分式が次の (有効な!) 順序で評価される場合、プログラムは未定義の動作をします。

  1. xxの右側のオペランドとしての値を計算するために読み取られます+

  2. xxのオペランドとしての値を計算するために読み取られます--

  3. xxデクリメントされた後の新しい値を格納するために書き込まれます

  4. fooと呼ばれる

ここでの唯一のシーケンス ポイントは、ステップ 3 と 4 の間です。引数式が評価された後、関数が呼び出される前です。xは 2 回読み取られ ([1] および [2])、1 回書き込まれます ([3])。読み取りの 1 つ ([1]) は、格納される新しい値を計算する目的ではないため、動作は未定義です。

評価順序は指定されていませんが、この評価順序が使用される順序である場合、プログラムは未定義の動作をします。

同じ理由が 2 番目のプログラムにも等しく当てはまります。

この式は の値を変更しないため、x - 1への引数として使用するのが最適です。foox

于 2012-08-21T21:40:54.773 に答える
0

はい、まったく減りません。

    else return foo(x--)+x;

関数を呼び出す行では、ポスト デクリメントを使用します。これは、値 10 が最初に次の関数に渡され、その後デクリメントされることを意味します。これは、関数が返されないため発生しません。

于 2012-08-21T21:32:45.077 に答える
0

呼び出し

foo(--x)

すでにデクリメントされた値で関数を呼び出しますが、

foo(x--)

常に元の値 (つまり 10) で呼び出すため、ゼロに近づくことはありません。これが理由です。

于 2012-08-21T21:33:03.763 に答える