汇编程序问题求助:计算可被3整除元素的和与计数出错
汇编程序调试求助:计算可被3整除元素的平均值
需求
分配并初始化20个范围在[20-200]的vector元素,计算并打印其中可被3整除元素的平均值。
问题描述
程序无法正常运行,运行后显示可被3整除元素的和为0,计数为1。操作步骤如下:
- 将从标准输入读取的数字以ASCII格式存储
- 遍历数组,将每个元素转换为二进制
- 通过除以3检查元素是否可被整除
代码
DOSSEG .MODEL SMALL .STACK 32 .DATA VECTOR DB 5 DUP(20H,20H,20H) ;20 DE NR PE MAXIM 3 CIFRE KBD DB 4,0,0,0,0,0 TEN_POWER DW 100,10,1 NUMERE DB 0Dh,0Ah,'Nr=$' MEDIE_ELEM_DIV3 DB 0 NR_ELEMENTE_DIV3 DB 0 SUMA DW 0 MSJ_SUMA DB 'SUMA=$' FLAG DB 0 MSJ_CONTOR DB 'NR_DIV3=$' NUMAR DW 0 NUMASC DB 0Dh,0Ah,'Suma= $' .CODE START: MOV AX, @DATA MOV DS, AX CALL CITESTE CALL CRLF CALL AFISARE CALL CRLF CALL SUMA_NUMERE CALL AFISARE_SUMA CALL CRLF CALL AFISARE_CONTOR MOV AH, 4CH INT 21H CITESTE: MOV CX, 5 MOV DI,(OFFSET VECTOR)+3 AGAIN: PUSH CX MOV DX,OFFSET NUMERE MOV AH,9 INT 21H ; afiseaza sir de interogare MOV [KBD+1],0 MOV AH,0Ah MOV DX,OFFSET KBD INT 21H ; citeste numar cu 1 pana la 3 cifre MOV CL,[KBD+1] MOV CH,0 MOV SI,(OFFSET KBD)+2 PUSH DI SUB DI,CX NEXT: MOV AL,[SI] MOV [DI],AL INC SI ; memoreaza numar INC DI LOOP NEXT POP DI ADD DI,3 POP CX LOOP AGAIN RET AFISARE: MOV CX, 5 MOV SI,OFFSET VECTOR DISP: CALL CRLF PUSH CX MOV CX,3 NUM: MOV AH,2 MOV DL,[SI] INT 21h ; afiseaza sirul de numere INC SI LOOP NUM POP CX LOOP DISP RET CRLF: MOV AH,2 MOV DL,0Ah INT 21h MOV AH,2 MOV DL,0Dh INT 21h RET SUMA_NUMERE: MOV CX, 5 ;ITERARE CELE 20 ELEM VECTOR MOV SUMA, 0 ; INITIALIZARE CU 0 MOV [NR_ELEMENTE_DIV3], 0 MOV BP, 0 ASC_BIN: PUSH CX MOV CX, 3 ;AM 3 CIFRE MOV BX, 10 MOV SI, OFFSET VECTOR AGAIN2: MOV AX,[NUMAR] MUL BX ; inmulteste suma partiala cu 10 MOV DL,[SI] MOV DH,0 AND DL,0FH ; conversie ASCII binar pentru cifra curenta ADD AX,DX ; aduna cifra curenta MOV [NUMAR],AX ;NUMAR E NR MEU IN BINAR LOOP AGAIN2 POP CX CMP BP, 35H JE END INC BP CONDITIE_DIV3: XOR AX,AX MOV AX,[NUMAR] ;PUN IN AX NR IN BINAR MOV BL, 3 DIV BL ;IMPART ELEMENTUL LA 3 CMP AH, 0 ;COMPAR RESTUL CU 0 JNE NU_E_DIV3 ADD [SUMA], AX ;ADAUGA IN SUMA NR DIV 3 ADD [NR_ELEMENTE_DIV3], 1 INC SI NU_E_DIV3: INC SI JMP AGAIN2 END: RET AFISARE_SUMA: BIN_ASC: MOV CX,4 ; din numere binare pe 16 biti ; pot rezulta siruri ASCII cu 5 cifre MOV SI,OFFSET TEN_POWER ; pointer spre tabela puterilor lui 10 MOV DI,(OFFSET NUMASC)+7 NEXT3: MOV AX,[SUMA] MOV DX,0 ; pregateste deimpartitul pe 32 de biti DIV WORD PTR [SI] ; obtine catul curent MOV [SUMA],DX ; salveaza restul curent OR AL,30H ; salveaza codul ASCII al cifrei curente MOV [DI],AL INC DI ADD SI,2 ; avanseaza pointerul spre urmatoarea putere a lui 10 LOOP NEXT3 OR DL,30H ; salveaza codul ASCII al ultimei cifre (cifra unitatilor) MOV [DI],DL MOV AH, 09h MOV DX, OFFSET NUMASC INT 21H RET AFISARE_CONTOR: AND [NR_ELEMENTE_DIV3], 0FH ; masca ultimii 4 biti - obtinem cifra coresp caracterului MOV AH, 2 ;pregatire pt afisarea caracterului MOV DL, 0DH ; carriage return INT 21H ;apelarea intreruperii MOV AH, 2 MOV DL, 0AH ;line feed INT 21H REZULTAT: MOV AH, 9 ;pregatirea pentru afisarea unui string MOV DX, OFFSET MSJ_CONTOR ;sirul FINAL 'NR_DIV3=' INT 21H MOV AL, [NR_ELEMENTE_DIV3] ;NUMARUL MOV AH, 0 ; deimpartitul este ax MOV BL, 10 ;impartitorul DIV BL ;imparitm ax la bl -> al = catul si ah = restul PUSH AX ;salvez pe stiva rez impartirii CMP AL, 0 ;daca suma are o singrua cifra JE O_CIFRA ; sare si nu o mai afiseaza pe prima MOV DL, AL ; pt afisarea catului, adica a primei cifre din suma OR DL, 30H ;codul ascii al caracterului coresp cifrei din tabela ascii MOV AH, 2 INT 21H O_CIFRA: POP AX ;scoate din stiva continutul reg ax MOV DL, AH ;pt afisarea restului, adica celei de a doua cifre OR DL, 30H ;obtinerea caract corespunzator MOV AH, 2 ;pregatirea pt afisare INT 21H ;apelarea intreruperii RET END START
错误分析与修正方案
1. 数组定义与循环次数不匹配
- 问题:需求是20个元素,但
VECTOR定义为5 DUP(20H,20H,20H),仅生成15字节(5个3位数字),且CITESTE、AFISARE、SUMA_NUMERE中的CX都设为5,和需求的20个元素不符。 - 修正:将数组改为
VECTOR DB 20 DUP(3 DUP(20H))(20个元素,每个占3字节),同时把相关子程序的CX初始值改为20。
2. SUMA_NUMERE子程序核心逻辑错误
- 问题1:SI指针被重复重置
在ASC_BIN中每次循环都执行MOV SI, OFFSET VECTOR,导致始终处理数组第一个元素,无法遍历整个数组。 - 问题2:NUMAR变量未重置
每次转换新元素的ASCII到二进制时,NUMAR没有清零,导致后续元素的数值是基于前一个元素累加的错误值。 - 问题3:循环终止条件错误
使用CMP BP, 35H作为终止条件完全不合理,应该用CX控制元素遍历次数。 - 问题4:指针推进错误
每个元素占3字节,处理完一个元素后SI应该增加3,而非INC SI一次。 - 问题5:累加操作错误
DIV BL是字节除法,商存在AL中,直接ADD [SUMA], AX会把AX的高8位(随机值)也加进去,应该先将AL零扩展为AX再累加。
修正后的SUMA_NUMERE子程序:
SUMA_NUMERE: MOV CX, 20 ; 遍历20个元素 MOV SUMA, 0 ; 初始化和为0 MOV [NR_ELEMENTE_DIV3], 0 MOV SI, OFFSET VECTOR ; SI指向数组起始位置 PROCESS_ELEMENT: MOV NUMAR, 0 ; 每次处理新元素前清零NUMAR PUSH CX MOV CX, 3 ; 每个元素3位数字 MOV BX, 10 CONVERT_ASC_BIN: MOV AX, NUMAR MUL BX ; 数值*10 MOV DL, [SI] AND DL, 0FH ; ASCII转二进制 MOV DH, 0 ADD AX, DX MOV NUMAR, AX INC SI LOOP CONVERT_ASC_BIN POP CX ; 检查是否可被3整除 MOV AX, NUMAR MOV BL, 3 DIV BL CMP AH, 0 JNE SKIP_ADD ; 累加符合条件的元素 MOV AH, 0 ADD SUMA, AX ; 零扩展AL为AX后累加 INC [NR_ELEMENTE_DIV3] SKIP_ADD: LOOP PROCESS_ELEMENT ; 处理下一个元素 RET
3. AFISARE_CONTOR子程序错误
- 问题:
AND [NR_ELEMENTE_DIV3], 0FH会清零高4位,当计数超过9时会丢失数值(比如10会变成0)。 - 修正:删除这行代码,直接使用原始计数值即可。
4. AFISARE_SUMA子程序问题
- 问题:该子程序修改了
SUMA变量的值,导致后续如果要计算平均值时,原始和已经被破坏。 - 修正:将
SUMA的值复制到临时变量中再处理,比如:
AFISARE_SUMA: MOV AX, SUMA MOV BX, AX ; 保存原始SUMA值到BX BIN_ASC: MOV CX, 4 MOV SI, OFFSET TEN_POWER MOV DI, (OFFSET NUMASC)+7 MOV SUMA, BX ; 恢复SUMA的原始值 NEXT3: MOV AX, SUMA MOV DX, 0 DIV WORD PTR [SI] MOV SUMA, DX OR AL, 30H MOV [DI], AL INC DI ADD SI, 2 LOOP NEXT3 OR DL, 30H MOV [DI], DL MOV AH, 09h MOV DX, OFFSET NUMASC INT 21H RET
5. 补充平均值计算
原程序未实现平均值计算,可在SUMA_NUMERE之后添加:
; 计算平均值 MOV AL, [NR_ELEMENTE_DIV3] MOV AH, 0 CMP AX, 0 JE SKIP_AVERAGE ; 避免除以0 MOV AX, SUMA DIV WORD PTR [NR_ELEMENTE_DIV3] MOV MEDIE_ELEM_DIV3, AL ; 打印平均值(可参考AFISARE_CONTOR的逻辑实现) SKIP_AVERAGE:
内容的提问来源于stack exchange,提问作者ioana
相关产品推荐
相关产品推荐

