VerySource

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 719|回复: 2

王爽汇编里的课程设计为何我写的程序显示的是乱码?

[复制链接]

2

主题

4

帖子

5.00

积分

新手上路

Rank: 1

积分
5.00
发表于 2020-1-3 15:00:01 | 显示全部楼层 |阅读模式
以下程序是王爽汇编里的课程设计我写了n多遍,改了好几天了,就是总达不到想要的结果,请问各位高手哪个地址错了?

程序任务:
将以下数据显示在屏幕上
年份         年总收入             员工人数              人均收入
1975          16                      3                    ?
1976          22                      7                    ?
1977          382                     9                    ?
1978          1356                    13                   ?
1979          2390                    28                   ?
1980          8000                    38                   ?
1981          16000                   130                  ?
1982          24486                   220                  ?
1983          50065                   476                  ?
1984          97479                   778                  ?
1985          140417                  1001                 ?
1986          197514                  1442                 ?
1987          345980                  2258                 ?
1988          590827                  2793                 ?
1989          803530                  4037                 ?
1990          1183000                 5635                 ?
1991          1843000                 8226                 ?
1992          2759000                 11542                ?
1993          3753000                 14430                ?
1994          4649000                 15257                ?
1995          5937000                 17800                ?


程序:
assume cs:code
data segment
     db '1975','1976','1977','1978','1979','1980','1981','1982'   
     db '1983','1984','1985','1986','1987','1988','1989','1990'
     db '1991','1992','1993','1994','1995',0
     ;以上是表示21年的21个字符串
     dd 16,22,382,1356,2390,8000,16000,24486
     dd 50065,97479,140417,197514,345980,590827,803530,1183000
     dd 1843000,2759000,3753000,4649000,5937000
     ;以上是表示21年公司总收的21个dword型数据
     dw 3,7,9,13,28,38,130,220
     dw 476,778,1001,1442,2258,2793,4037,5635
     dw 8226,11542,14430,15257,17800
     ;以上是表示21年公司雇员人数的21个word型数据
data ends
tempdata segment
     db 8 dup(0)
tempdata ends
code segment
start:mov ax,data
     mov ds,ax ;将数据段data段地址送入ds
     mov ax,0b800h
     mov es,ax ;将显存基地址送入es
     sub cx,cx ;将cx清0
     mov bx,0  ;把数据段data偏移地址指向data:0
     mov di,0  ;把显存偏移地址指向b800:0
     mov si,0  ;雇员地址偏移量
throwout:mov cl,ds:[bx]
         jcxz finished   ;检测数据是否显示完毕,若是转到finished
         mov dl,02h
         mov al,ds:[bx]
         mov es:[di],al
         mov es:[di+1],dl  ;将年份字段第一个字符送入显存es:[di]
         mov al,ds:[bx+1]
         mov es:[di+2],al
         mov es:[di+3],dl;将年份字段第二个字符送入显存es:[di+2]
         mov al,ds:[bx+2]
         mov es:[di+4],al
         mov es:[di+5],dl;将年份字段第三个字符送入显存es:[di+4]
         mov al,ds:[bx+3]
         mov es:[di+6],al
         mov es:[di+7],dl;将年份字段第四个字符送入显存es:[di+6]
         mov ax,ds:[bx+55h]
         mov dx,ds:[bx+57h];将收入总数字段dd送入寄存器dx(高16位)、ax(低16位)
         mov bp,32       ;将偏移地址指向收入总数字段的第一个单元地址
         call dtoc       ;调用子程序dtoc,将收入总数字段送入显存es:[sp+di]
         mov ax,ds:[si+0a9h]
         mov dx,0        ;将雇员字段dw送入寄存器ax
         call getbp      ;调用子程序getbp,计算每条记录雇员字段在显存中的起始地址
         call dtoc       ;调用子程序dtoc,将雇员字段送入显存es:[sp+di]
         mov ax,ds:[bx+55h]
         mov dx,ds:[bx+57h]
         mov cx,bx
         mov bx,ds:[si+0a9h];将收入总数字段dd送入寄存器dx(高16位)、ax(低16位),将雇员字段dw送入寄存器bx
         call divdw      ;调用子程序divdw,计算人均收入的值
         mov bx,cx
         mov cx,0
         call getbp      ;调用子程序getbp,计算每条记录人均收入字段在显存中的起始地址
         call dtoc       ;调用子程序dtoc,将人均收入字段送入显存es:[sp+di]
         add bx,4
         add si,2
         add di,160       ;以上3句是为下一次循环时存放数据做准备
         jmp throwout    ;若数据未显示完毕,跳转至throwout进入下次循环
finished:mov ax,4c00h    ;数据显示完毕,返回dos
         int 21h
;以下是子程序dtoc,功能:将数字型数据转换成字符,并将其送入显存;参数:dd数据(用ax,dx传送),每条记录在显存中的偏移量bp,di;返回:每条记录在显存中的偏移量bp,为下一字段做准备
dtoc:push si
     push ds
     push bx
     push cx
     mov si,0
     mov bx,tempdata
     mov ds,bx
   s:mov cx,ax
     jcxz ok
     mov bx,0ah
     call divdw
     add cl,30h
     mov ds:[si],cl
     inc si
     jmp s
  ok:mov bh,02h
     mov cx,si
   a:mov bl,ds:[si]
     mov es:[bp+di],bl
     mov es:[bp+di+1],bh
     sub si,1
     add bp,2
     loop a
     pop cx
     pop bx
     pop ds
     pop si
     ret
;以下是子程序divdw,计算两数值的商及余数
divdw:push si ;ax,dx,bx   ax,dx,cx
      push ax
      mov ax,dx
      mov dx,0
      div bx
      mov si,ax
      pop ax
      div bx
      mov cx,dx
      mov dx,si
      pop si
      ret
;以下是子程序getbp,偏移量bp的值
getbp:push ax  ;bp   bp
      push bx
      mov ax,bp
      mov bx,0
      mov bl,32
      div bl
      sub bl,ah
      add bp,bx
      pop bx
      pop ax
      ret
code ends
end start
回复

使用道具 举报

0

主题

23

帖子

17.00

积分

新手上路

Rank: 1

积分
17.00
发表于 2020-1-4 03:06:01 | 显示全部楼层
大致有两个问题吧. 第一是在 throwout: 循环中, 在计算平均值时, 将 bx 通过 cx 来进行保存, 但 divdw 子程却是使用了 cx 的, 所以 cx 的值发生改变了. 这个保存失效. 可以通过堆栈来进行 "保存-恢复":
...
         mov dx,ds:[bx+57h]
         push  bx    ;*  mov cx,bx    这里压栈保存 bx
         mov bx,ds:[si+0a9h]  ;将收入总数字段 ....
         call divdw      ;调用子程序divdw,计算人均收入的值
         pop   bx    ;*  mov bx,cx    这里出栈恢复 bx
         mov cx,0
...

第二个问题就是在 dtoc 子程中, 最后现实结果钱, si 指向的是有效字符串的后面. 比如第一个值 16, 转换后的字符串为 "61", si 指向的不是 '1' 而是 '1' 的后面一个字节. 所以 si 应该先减去 1:
...
  ok:mov bh,02h
     mov cx,si
     dec si    ;*+  这里!
   a:mov bl,ds:[si]
...
回复

使用道具 举报

2

主题

4

帖子

5.00

积分

新手上路

Rank: 1

积分
5.00
 楼主| 发表于 2020-2-3 19:30:01 | 显示全部楼层
感谢www_james指点
回复

使用道具 举报

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

本版积分规则

Archiver|手机版|CopyRight © 2008-2023|verysource.com ( 京ICP备17048824号-1 )

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