我用汇编语言(MASM)编写了一个程序,让学生练习计算组合。程序递归计算阶乘。我使用一个名为组合的过程接收n和r,然后得到(n = r)!,n!和r!通过调用名为factorial的过程。因子是递归的。
.data
n DWORD ?
r DWORD ?
result DWORD ?
answer DWORD ?
divisor DWORD ?
.code
MAIN PROC
(一些初步程序要求)
push OFFSET divisor ;ebp+20
push n ;ebp+16
push r ;ebp+12
push OFFSET result ;ebp+8
call combinations
;*************************************************
; combinations calls factorial (3 times) to calculate n!, r!, and (n-r)!.
; combinations calculates n!/(r!(n-r)!) , and stores the value in result.
; receives: accepts n and r by value and result by address.
; returns: none
; preconditions: none
; registers changed: eax, ebx, edx
;*************************************************
combinations PROC
push ebp
mov ebp,esp
mov eax, [ebp+16] ;find (n-r)!
sub eax, [ebp+12]
mov ebx, eax
push ebx
call factorial
pop ebx
mov edx,[ebp+20] ;move (n-r)! into result
mov [edx],eax
mov ebx, [ebp+12] ;find r!
push ebx
call factorial
pop ebx
mov edx,[ebp+20]
mov ebx, [edx]
mul ebx ;r!*(n-r)!, store product in eax
mov ebx, [ebp+20]
mov [ebx], eax ;store product in divisor variable
mov ebx, [ebp+16] ;find n!
push ebx
call factorial
pop ebx
mov edx,[ebp+20]
mov ebx,[edx] ;move value of divisor into ebx
mov edx, 0
div ebx ;divide n! by divisor (r!*(n-r)!)
mov ebx, [ebp+8]
mov [ebx],eax ;move quotient into result
pop ebp
ret 16
combinations ENDP
;*************************************************
; calculates factorial recursively
; receives:
; returns: factorial solution in eax
; preconditions: none
; registers changed: eax
;*************************************************
factorial PROC
mov eax,dword ptr [esp+4]
cmp eax,1
jle endRecursive
dec eax
push eax
call factorial
mov esi,dword ptr [esp+4]
mul esi
endRecursive:
ret 4
factorial ENDP
一切按预期进行,我得到了所需的值。但是,当完成所有计算并且程序在组合过程结束时到达语句“ret 16”时,我得到以下异常:
Project.exe中0x76f915de处的未处理异常:0xC0000005:访问冲突。
我通过调试器运行它并尝试在我错误计算的情况下更改return语句,但到目前为止我没有尝试过任何工作。也许这是一个盯着这个太长时间的情况,但任何想法都会受到赞赏。提前谢谢。
更新:只需在调试器中跟踪ebp和esp:看起来当程序出现在最后一个因子调用时,esp是ebp的+12,所以每次调用时都会增加+4阶乘。结果,当程序点击pop ebp时,ebp指向r而不是它应该的位置。有关如何解决此问题的任何建议吗?
答案 0 :(得分:3)
您需要删除在对pop ebx
的三个顶级调用之后显示的三条factorial
说明。由于factorial
已经将其参数从堆栈中弹出(通过使用ret 4
),因此尝试通过执行pop ebx
再次删除参数会使堆栈指针混乱。