对于以下代码,我期望控制台输出
Loop 3
Loop 2
Loop 1
但是,相反
Loop 3
Loop 2
Loop 1
Loop 1
显示。 我了解这是一种递归方法,即调用自身。只是努力了解它是如何工作的。这是我苦苦挣扎的考试题。
我尝试调试,发现发生以下情况:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WhileLoopExample
{
class Program
{
private static int WriteToConsole(int Lemmings)
{
int i = Lemmings;
while (i > 0)
{
Console.WriteLine("loop {0}", i);
i = WriteToConsole(i - 1);
}
return Lemmings - 1;
}
static void Main(string[] args)
{
WriteToConsole(3);
Console.ReadKey();
}
}
}
答案 0 :(得分:3)
您的问题是您不了解功能激活的概念。该功能的每次激活都有其自己的i
副本和其自己的Lemmings
副本,并且它们完全独立于其他所有函数激活。
这里让您感到困惑的是,您有五个-是的五个-对WriteToConsole
的不同呼叫,并且所有呼叫都有自己的 i
的副本及其lemmings
的自己副本。让我们通过对程序进行检测以显示每个不同的函数激活以及每个变量在每个点的值来说明这一点:
public class Program
{
private static int callCount = 0;
private static int WriteToConsole(int lemmings)
{
callCount += 1;
int currentCall = callCount;
Console.WriteLine("Call number {0} has Lemmings = {1}", currentCall, lemmings);
int i = lemmings;
Console.WriteLine("Call number {0} has i = {1}", currentCall, i);
while (i > 0)
{
Console.WriteLine("Call number {0} in the loop top with i = {1}", currentCall, i);
i = WriteToConsole(i - 1);
Console.WriteLine("Call number {0} in the loop bottom with i = {1}", currentCall, i);
}
Console.WriteLine("Call number {0} is about to return {1}", currentCall, lemmings - 1);
return lemmings - 1;
}
public static void Main(string[] args)
{
WriteToConsole(3);
}
}
现在,我们可以看到输出反映了正在发生的事情:
Call number 1 has Lemmings = 3
Call number 1 has i = 3
Call number 1 in the loop top with i = 3
Call number 2 has Lemmings = 2
Call number 2 has i = 2
Call number 2 in the loop top with i = 2
Call number 3 has Lemmings = 1
Call number 3 has i = 1
Call number 3 in the loop top with i = 1
Call number 4 has Lemmings = 0
Call number 4 has i = 0
Call number 4 is about to return -1
Call number 3 in the loop bottom with i = -1
Call number 3 is about to return 0
Call number 2 in the loop bottom with i = 0
Call number 2 is about to return 1
Call number 1 in the loop bottom with i = 1
Call number 1 in the loop top with i = 1
Call number 5 has Lemmings = 0
Call number 5 has i = 0
Call number 5 is about to return -1
Call number 1 in the loop bottom with i = -1
Call number 1 is about to return 2
非常仔细地阅读跟踪信息,直到您了解发生了什么。您获得loop x
的四个输出,因为当i
为3时,调用编号1在循环顶部,而在递归调用之后,i
为1。满足循环条件,因此调用1同时打印loop 3
和loop 1
。
答案 1 :(得分:2)
在递归调用中,您传入i - 1
。即为Lemmings
-您以Lemmings - 1
的形式返回。
正在发生两个-1
-是您想要的吗?
但是,如果您看看发生了什么事
第一个呼叫的Lemmings
为3
,i
为3
。
Loop 3
已写出。
然后递归,传入3-1
:
第二个呼叫的Lemmings
为2
,而i
为2
。
Loop 2
已写出。
然后递归,传入2-1
:
第三个呼叫的Lemmings
为1
,i
为1
。
Loop 1
已写出。
然后递归,传入1-1
:
第四次呼叫将Lemmings
设为0
,将i
设为0
。
未输入while
,因此返回了0-1
。
回到第三个通话中:
i
被分配了-1
,所以结束了。
第三个调用返回1-1
。
回到第二个通话内:
i
被分配了0
,所以结束了。
第二个呼叫返回2-1
。
返回第一个电话内
i
被分配了1
,所以持续一会儿。
Loop 1
已写出。
从这里继续执行,但是全部没有输出。以上就是为什么您得到两个Loop 1
的原因。
答案 2 :(得分:1)
这是因为您有一个循环 并且您有递归。您应该摆脱对WriteToConsole(i)
中对WriteToConsole
的调用,或者摆脱循环并坚持递归。
此外,您可以使用递归调用的返回值来影响i
,从而影响while
循环。我认为这是造成您困惑的主要原因。
幸运的是,它仅需几个步骤,因此可以很容易地将其分解。这就是发生的情况。暗示了while循环,我只描述输出,对i的修改以及递归调用。
You call WriteToConsole(3); // Let's call this 'instance' of the function call 'A'
A prints "Loop 3"
A calls WriteToConsole(2); // Let's call this 'B'
B prints "Loop 2"
B calls WriteToConsole(1) // Let's call this 'C'
C prints "Loop 1"
C calls WriteToConsole(0); // Let's call this 'D'
D doesn't enter it's loop.
D returns -1 (Lemmings - 1, where Lemmings is 0), i becomes -1 in C
C's loop ends because i is -1
C returns 0, i becomes 0 in B
B's loop ends, because i is 0
B returns 1, i becomes 1 in A
A is still in the loop, since its 'i' > 0, so..
A prints "Loop 1" (again)
A calls WriteToConsole(0); // Let's call this 'E'
E returns -1, i becomes -1 in A
A returns 2, this value is ignored in your main function.
End of program
答案 3 :(得分:0)
要实现所需的功能,在这种情况下,您需要一种循环或其他迭代机制,既可以通过递归(没有while
),也可以通过{{ 1}}(但是没有递归)。
这是while
的解决方案,无需递归:
while
正在运行的DotNetFiddle:https://dotnetfiddle.net/kR4th0