You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

汇编程序问题求助:计算可被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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 05:57:01