递归方法
Recursive methods
我很难掌握递归。例如我有以下方法。当 if 语句 return 为真时,我希望从该方法中得到 return。但是查看 Windbg 中的方法执行,Visual Studio 表明该方法继续执行。对于一般性问题,我深表歉意,但非常感谢您的反馈。
N如何递减以满足if条件?
long factorial(int N)
{
if(N == 1)
return 1;
return N * factorial(N - 1);
}
我认为最好的掌握方法是手动完成代码。假设你调用 factorial(4),会发生什么?4 不等于 1。Return 4 * factorial(4-1).
阶乘 3 的 return 值是多少? 3 不等于 1 return 3* 阶乘(3-1).
阶乘 2 的 return 值是多少? 2 不等于 1 return 2* 阶乘(2-1).
阶乘 1 的 return 值是多少? 1 等于 1 为真。 Return 1. 这是基本情况。现在我们回到递归。
Return 1. 这是阶乘 (2-1)
Return2*1。这是阶乘 (3-1)
Return 3*2 这是阶乘(4-1)
Return 4*6 这是 factorial(4),你最初的调用。
你的想法是你有一个具有基本情况的函数(当 n=1 return 1 时)并且该函数以将函数移向基本情况的方式调用自身(阶乘(n** -**1))。
编译和反汇编函数你应该得到一个类似这样的反汇编
0:000> cdb: Reading initial command 'uf fact!fact;q'
fact!fact:
00401000 55 push ebp
00401001 8bec mov ebp,esp
00401003 837d0801 cmp dword ptr [ebp+8],1
00401007 7507 jne fact!fact+0x10 (00401010)
fact!fact+0x9:
00401009 b801000000 mov eax,1
0040100e eb13 jmp fact!fact+0x23 (00401023)
fact!fact+0x10:
00401010 8b4508 mov eax,dword ptr [ebp+8]
00401013 83e801 sub eax,1
00401016 50 push eax
00401017 e8e4ffffff call fact!fact (00401000)
0040101c 83c404 add esp,4
0040101f 0faf4508 imul eax,dword ptr [ebp+8]
fact!fact+0x23:
00401023 5d pop ebp
00401024 c3 ret
quit:
让我们假设在输入函数时 N == 5 即 [ebp+8] 将保留 5
只要 [ebp+8] > 1 jne 就会被占用
在这里你可以看到 N 正在递减 (sub eax ,1)
递减的 N 再次传递给函数 fact(在没有 return 的情况下递归返回给调用者)循环再次发生并且递减的 N 被重新发送到 fact 这一直发生直到 jne 不被采用,直到 N 或[ebp+8] == 1
当N变为1时jne不被取而jmp 401023被取
其中 returns 到调用者调用者是函数 fact(int N)
那就是 return 40101c,其中 eax 的乘法发生,结果存储回 eax;
这将一直发生,直到 ret 指向 main() 中的第一个调用,请在第一次执行 pop ebp 之前查看下面的堆栈
0:000> kPL
ChildEBP RetAddr
0013ff38 0040101c fact!fact(
int N = 0n1)+0x23
0013ff44 0040101c fact!fact(
int N = 0n2)+0x1c
0013ff50 0040101c fact!fact(
int N = 0n3)+0x1c
0013ff5c 0040101c fact!fact(
int N = 0n4)+0x1c
0013ff68 0040109f fact!fact(
int N = 0n5)+0x1c
0013ff78 0040140b fact!main(
int argc = 0n2,
char ** argv = 0x00033ac0)+0x6f
我很难掌握递归。例如我有以下方法。当 if 语句 return 为真时,我希望从该方法中得到 return。但是查看 Windbg 中的方法执行,Visual Studio 表明该方法继续执行。对于一般性问题,我深表歉意,但非常感谢您的反馈。
N如何递减以满足if条件?
long factorial(int N)
{
if(N == 1)
return 1;
return N * factorial(N - 1);
}
我认为最好的掌握方法是手动完成代码。假设你调用 factorial(4),会发生什么?4 不等于 1。Return 4 * factorial(4-1).
阶乘 3 的 return 值是多少? 3 不等于 1 return 3* 阶乘(3-1).
阶乘 2 的 return 值是多少? 2 不等于 1 return 2* 阶乘(2-1).
阶乘 1 的 return 值是多少? 1 等于 1 为真。 Return 1. 这是基本情况。现在我们回到递归。 Return 1. 这是阶乘 (2-1) Return2*1。这是阶乘 (3-1) Return 3*2 这是阶乘(4-1) Return 4*6 这是 factorial(4),你最初的调用。
你的想法是你有一个具有基本情况的函数(当 n=1 return 1 时)并且该函数以将函数移向基本情况的方式调用自身(阶乘(n** -**1))。
编译和反汇编函数你应该得到一个类似这样的反汇编
0:000> cdb: Reading initial command 'uf fact!fact;q'
fact!fact:
00401000 55 push ebp
00401001 8bec mov ebp,esp
00401003 837d0801 cmp dword ptr [ebp+8],1
00401007 7507 jne fact!fact+0x10 (00401010)
fact!fact+0x9:
00401009 b801000000 mov eax,1
0040100e eb13 jmp fact!fact+0x23 (00401023)
fact!fact+0x10:
00401010 8b4508 mov eax,dword ptr [ebp+8]
00401013 83e801 sub eax,1
00401016 50 push eax
00401017 e8e4ffffff call fact!fact (00401000)
0040101c 83c404 add esp,4
0040101f 0faf4508 imul eax,dword ptr [ebp+8]
fact!fact+0x23:
00401023 5d pop ebp
00401024 c3 ret
quit:
让我们假设在输入函数时 N == 5 即 [ebp+8] 将保留 5 只要 [ebp+8] > 1 jne 就会被占用
在这里你可以看到 N 正在递减 (sub eax ,1) 递减的 N 再次传递给函数 fact(在没有 return 的情况下递归返回给调用者)循环再次发生并且递减的 N 被重新发送到 fact 这一直发生直到 jne 不被采用,直到 N 或[ebp+8] == 1
当N变为1时jne不被取而jmp 401023被取 其中 returns 到调用者调用者是函数 fact(int N)
那就是 return 40101c,其中 eax 的乘法发生,结果存储回 eax;
这将一直发生,直到 ret 指向 main() 中的第一个调用,请在第一次执行 pop ebp 之前查看下面的堆栈
0:000> kPL
ChildEBP RetAddr
0013ff38 0040101c fact!fact(
int N = 0n1)+0x23
0013ff44 0040101c fact!fact(
int N = 0n2)+0x1c
0013ff50 0040101c fact!fact(
int N = 0n3)+0x1c
0013ff5c 0040101c fact!fact(
int N = 0n4)+0x1c
0013ff68 0040109f fact!fact(
int N = 0n5)+0x1c
0013ff78 0040140b fact!main(
int argc = 0n2,
char ** argv = 0x00033ac0)+0x6f