鱼C论坛

 找回密码
 立即注册
查看: 391|回复: 3

[已解决]汇编实验7,死循环,debug只显示年份,整一天了,不知道哪出错了,求指点

[复制链接]
发表于 2024-8-7 17:21:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
assume cs:code,ds:data,es:table
data segment
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995';84(0~53H)
;21年的21个字符串
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000.4649000,5937000
;21年公司总收入的21个dword型数据;84(54H~0A7H)
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226;84;错误是42,前面一共210
dw 11542,14430,15257,17800;(0A8H~0D1H)
;21年雇佣人数的21个word型数据
data ENDS

;存放数据
table segment
db 21 dup('year summ ne ?? ')
table ENDS

code segment
start: mov ax,data
       mov ds,ax

       mov ax,table
       mov es,ax
        
       mov bx,0  
       mov si,0
       mov di,0
       mov cx,21
s:     mov ax,[si];年份
       mov dx,[si+2]
       mov es:[bx],ax
       mov es:[bx+2],dx

       mov ax,[di+168];人数
       mov es:[bx+10],ax

       mov ax,[si+84];工资
       mov dx,[si+86]
       mov es:[bx+5],ax
       mov es:[bx+7],dx

       div word ptr es:[bx+10]
       mov es:[bx+13],ax
       add bx,16
       add si,4
       add di,2
       loop s
       mov ax,2C00H
       int 21H
code ends
end start
最佳答案
2024-8-7 18:24:04
1.
从您提供的代码和描述中,我可以看到几个潜在的问题点,这些问题可能导致程序陷入死循环或者不能正确执行。下面是逐一分析和建议的修改:

数据读取错误:
您的代码中使用了 mov ax,[si] 来读取年份,但实际上您的年份数据是以字节(byte)形式存储的,而不是字(word)。因此,您应该使用 mov al,[si] 来读取一个字节到 AL 寄存器,并使用 mov ah,0 来确保 AH 为0(如果您的年份都是两位数的话)。然后,您可以考虑如何存储这个年份(比如,直接存储到 ES:[BX] 的位置,或者将其转换为字符形式存储)。
数据偏移量计算:
您在计算收入和雇佣人数的偏移量时使用了固定的偏移量(如 [di+168] 和 [si+84]),但这看起来并不正确。这些偏移量应该基于 BX 或 SI 的当前值动态计算,特别是如果您希望按照年份的顺序来访问这些数据。
循环控制:
您使用了 loop s 指令,但没有设置循环计数器(CX)。在 s 标签之前,您已经设置了 CX 为 21,这是正确的,但请确保在 loop 指令执行之前 CX 的值没有被意外修改。
除法操作:
您在使用 div 指令进行除法运算时,必须确保除数(这里是 es:[bx+10])不为零,否则会导致除零错误。您可能需要在执行除法之前检查除数是否为零。
字符存储:
如果您希望将年份、收入和雇佣人数转换为字符串形式存储在 table 段中,您需要编写额外的代码来处理这种转换。
下面是一个简化的示例,仅展示如何正确读取年份并存储到 table 段中(注意,这里未处理其他数据和转换):

asm
assume cs:code, ds:data, es:table  
  
data segment  
    db '1975', '1976', ... ; 年份数据  
data ends  
  
table segment  
    db 21 dup('????') ; 预留空间存储年份字符串  
table ends  
  
code segment  
start:  
    mov ax, data  
    mov ds, ax  
  
    mov ax, table  
    mov es, ax  
  
    mov bx, 0      ; ES:BX 指向 table 段  
    mov cx, 21     ; 循环次数  
    mov si, 0      ; DS:SI 指向年份数据  
  
s:  mov al, [si]   ; 读取年份的第一个字节  
    mov es:[bx], al  
    inc si  
  
    mov al, [si]   ; 读取年份的第二个字节  
    mov es:[bx+1], al  
    inc si  
  
    add bx, 2      ; 移动到 table 段的下一个位置  
    loop s  
  
    mov ax, 4C00H  ; 退出到 DOS  
    int 21H  
code ends  
end start
请注意,这个示例仅处理年份的读取和存储,未涉及其他数据的处理。您需要根据实际需求进一步扩展和修改代码。
2.
assume cs:code, ds:data, es:table
data segment
years db '1975','1976','1977',... ; 继续到1995
incomes dd 16,22,...; 收入数据
employees dw 3,7,...; 人员数据
data ends

table segment
db 21 dup('year summ ne ?? ')
table ends

code segment
start:
    mov ax, data
    mov ds, ax

    mov ax, table
    mov es, ax
    
    mov cx, 21          ; 设置循环次数为21
    xor bx, bx          ; bx 用于存储偏移量,初始为0
    xor si, si          ; si 用于年数据偏移
    xor di, di          ; di 用于人员数据偏移

s:
    ; 读取年份
    mov al, [years + si]  ; 读取年份
    mov [es:bx], al       ; 存入 table
    inc si                 ; 移动到下一个年份
    add bx, 16             ; 更新表格位置

    ; 读取人数
    mov ax, [employees + di]
    mov [es:bx], ax
    add di, 2              ; 更新偏移
    add bx, 2              ; 更新表格位置

    ; 读取收入
    mov eax, [incomes + si]
    ; 修改计算逻辑,根据需要进行计算

    ; 检查循环是否完成
    loop s                 ; 如果 cx 不为0,则继续循环

    ; 程序结束
    mov ax, 2C00H
    int 21H

code ends
end start
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-8-7 17:23:01 | 显示全部楼层
看起来你的汇编代码让你陷入了一个死循环,别担心,我们来一起看看问题出在哪里。首先,我们需要确保代码逻辑清晰,避免在循环中没完没了地转圈。

从你提供的代码来看,有几个地方可能会导致问题:

1. **数据段定义错误**:你表示年份、人数和工资的方式可能有误。`mov ax,;年份`、`mov ax,;人数` 和 `mov ax,;工资` 这些行没有正确加载数据。你需要指定数据段中的具体位置,比如使用 `mov ax, [data segment]` 这样的形式来获取具体的数据。

2. **移动数据的方式**:在以下几行中:
mov es:,ax
   mov es:,dx
   这里应该是把数据存储到 `table` 段中,而不是简单地使用 `es` 段。不然程序将无法找到你想要输出的内容。

3. **循环计数器控制**:你用 `loop s` 来控制循环,但注意一定要确保 `cx` 的值能正确地减少到零。如果在循环中没有修改 `cx`,这个循环将永远不会结束。

4. **整合代码**:整理一下代码结构,便于代码的理解和调试。记得每当你修改数据段 (如 `si`, `di`, `bx`) 后,一定要注意它们目标地址是否合理。

下面是一个修正后的代码示例(注意这里是伪代码,可能需要根据你的具体需求进行调整):
assume cs:code, ds:data, es:table
data segment
years db '1975','1976','1977',... ; 继续到1995
incomes dd 16,22,...; 收入数据
employees dw 3,7,...; 人员数据
data ends

table segment
db 21 dup('year summ ne ?? ')
table ends

code segment
start:
    mov ax, data
    mov ds, ax

    mov ax, table
    mov es, ax
    
    mov cx, 21          ; 设置循环次数为21
    xor bx, bx          ; bx 用于存储偏移量,初始为0
    xor si, si          ; si 用于年数据偏移
    xor di, di          ; di 用于人员数据偏移

s:
    ; 读取年份
    mov al, [years + si]  ; 读取年份
    mov [es:bx], al       ; 存入 table
    inc si                 ; 移动到下一个年份
    add bx, 16             ; 更新表格位置

    ; 读取人数
    mov ax, [employees + di]
    mov [es:bx], ax
    add di, 2              ; 更新偏移
    add bx, 2              ; 更新表格位置

    ; 读取收入
    mov eax, [incomes + si]
    ; 修改计算逻辑,根据需要进行计算

    ; 检查循环是否完成
    loop s                 ; 如果 cx 不为0,则继续循环

    ; 程序结束
    mov ax, 2C00H
    int 21H

code ends
end start

这段代码进行了基本的结构调整以帮助你更易懂,也记得添加适时的注释。希望这可以帮助你找到并解决问题!如果还有其他疑问,毫不犹豫地问我吧!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-7 18:24:04 | 显示全部楼层    本楼为最佳答案   
1.
从您提供的代码和描述中,我可以看到几个潜在的问题点,这些问题可能导致程序陷入死循环或者不能正确执行。下面是逐一分析和建议的修改:

数据读取错误:
您的代码中使用了 mov ax,[si] 来读取年份,但实际上您的年份数据是以字节(byte)形式存储的,而不是字(word)。因此,您应该使用 mov al,[si] 来读取一个字节到 AL 寄存器,并使用 mov ah,0 来确保 AH 为0(如果您的年份都是两位数的话)。然后,您可以考虑如何存储这个年份(比如,直接存储到 ES:[BX] 的位置,或者将其转换为字符形式存储)。
数据偏移量计算:
您在计算收入和雇佣人数的偏移量时使用了固定的偏移量(如 [di+168] 和 [si+84]),但这看起来并不正确。这些偏移量应该基于 BX 或 SI 的当前值动态计算,特别是如果您希望按照年份的顺序来访问这些数据。
循环控制:
您使用了 loop s 指令,但没有设置循环计数器(CX)。在 s 标签之前,您已经设置了 CX 为 21,这是正确的,但请确保在 loop 指令执行之前 CX 的值没有被意外修改。
除法操作:
您在使用 div 指令进行除法运算时,必须确保除数(这里是 es:[bx+10])不为零,否则会导致除零错误。您可能需要在执行除法之前检查除数是否为零。
字符存储:
如果您希望将年份、收入和雇佣人数转换为字符串形式存储在 table 段中,您需要编写额外的代码来处理这种转换。
下面是一个简化的示例,仅展示如何正确读取年份并存储到 table 段中(注意,这里未处理其他数据和转换):

asm
assume cs:code, ds:data, es:table  
  
data segment  
    db '1975', '1976', ... ; 年份数据  
data ends  
  
table segment  
    db 21 dup('????') ; 预留空间存储年份字符串  
table ends  
  
code segment  
start:  
    mov ax, data  
    mov ds, ax  
  
    mov ax, table  
    mov es, ax  
  
    mov bx, 0      ; ES:BX 指向 table 段  
    mov cx, 21     ; 循环次数  
    mov si, 0      ; DS:SI 指向年份数据  
  
s:  mov al, [si]   ; 读取年份的第一个字节  
    mov es:[bx], al  
    inc si  
  
    mov al, [si]   ; 读取年份的第二个字节  
    mov es:[bx+1], al  
    inc si  
  
    add bx, 2      ; 移动到 table 段的下一个位置  
    loop s  
  
    mov ax, 4C00H  ; 退出到 DOS  
    int 21H  
code ends  
end start
请注意,这个示例仅处理年份的读取和存储,未涉及其他数据的处理。您需要根据实际需求进一步扩展和修改代码。
2.
assume cs:code, ds:data, es:table
data segment
years db '1975','1976','1977',... ; 继续到1995
incomes dd 16,22,...; 收入数据
employees dw 3,7,...; 人员数据
data ends

table segment
db 21 dup('year summ ne ?? ')
table ends

code segment
start:
    mov ax, data
    mov ds, ax

    mov ax, table
    mov es, ax
    
    mov cx, 21          ; 设置循环次数为21
    xor bx, bx          ; bx 用于存储偏移量,初始为0
    xor si, si          ; si 用于年数据偏移
    xor di, di          ; di 用于人员数据偏移

s:
    ; 读取年份
    mov al, [years + si]  ; 读取年份
    mov [es:bx], al       ; 存入 table
    inc si                 ; 移动到下一个年份
    add bx, 16             ; 更新表格位置

    ; 读取人数
    mov ax, [employees + di]
    mov [es:bx], ax
    add di, 2              ; 更新偏移
    add bx, 2              ; 更新表格位置

    ; 读取收入
    mov eax, [incomes + si]
    ; 修改计算逻辑,根据需要进行计算

    ; 检查循环是否完成
    loop s                 ; 如果 cx 不为0,则继续循环

    ; 程序结束
    mov ax, 2C00H
    int 21H

code ends
end start
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-8 01:15:19 | 显示全部楼层
本帖最后由 jackz007 于 2024-8-8 01:21 编辑
assume cs:code,ds:data,es:table

stack segment para stack 'STACK'
    db 400h dup(0)
stack ends

data segment para public 'DATA'
db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
db '1993','1994','1995'
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
dw 11542,14430,15257,17800
data ends

table segment para public 'TABLE'
db 21 dup('year summ ne ?? ')
table ends

code segment para public 'CODE'
; 初始化数据段地址
start: mov ax,data
       mov ds,ax
       mov ax,table
       mov es,ax
; 以年为单位,向 table 表传输 21 个年份
       xor si,si
       push si
       pop di
       cld
       mov cx,21
s1:    movsw
       movsw
       add di,12
       loop s1
; 向 table 表传输 21 年中,每一年的总收入
       mov di,5
       mov cx,21
s2:    movsw
       movsw
       add di,12
       loop s2
; 向 table 表传输 21 年中,每一年的雇员人数,并计算出人均收入,存入 table 表中
       xor bx,bx
       mov di,10
       mov cx,21
s3:    movsw
       mov ax,word ptr es:[bx+5]
       mov dx,word ptr es:[bx+7]
       div word ptr es:[bx+10]
       mov word ptr es:[bx+13],ax       
       add di,14
       add bx,16
       loop s3

       mov ax,4c00h
       int 21h
code ends
end start
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-24 10:09

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表