7.6问题
问题:[bx+idata]的灵活运用
编程,将datasg段中每个单词的头一个字母改成大写
assume cs:codesg,ds:datasg
datasg segment
db '1\. file '
db '2\. edit '
db '3\. search '
db '4, view '
db '5\. option '
db '6\. help '
datasg ends
code segment
start:......
codesg ends
end start
分析:
其中定义的字符串在内存中的存放是这样的:
1.png定义了6个字符串,每个长度都是16个字节,需要进行6次循环,用一个变量R定位行,用常量定位列。过程如下:
-
BX先存放第一行的地址
-
mov cx,6 因为总共有六行
-
s:改变第BX行,第3列的字母为大写改变BX的值使它指向下一行的地址。
-
loop
也就是说,使用bx作变量,定位每行的起始地址,用3定位要修改的列,用[bx+idata]的方式来对目标单元进行寻址
代码:
assume cs:codesg,ds:datasg
datasg segment
db '1\. file '
db '2\. edit '
db '3\. search '
db '4, view '
db '5\. option '
db '6\. help '
datasg ends
code segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,6
s:mov al,[bx+3] ;注意单位是字节,所以是al
and al,11011111b
mov [bx+3],al
add bx,16
loop s
mov ax,4c00h
int 21h
codesg ends
end start </pre>
7.7问题
问题:[bx+SI]的灵活运用
编程,将datasg段中每个单词改写成大写字母
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg ends
code segment
start:......
codesg ends
end start
分析:
其中定义的字符串在内存中的存放是这样的:
2.png在datasg中定义了4个字符串,每个长度为16个字节,因为他们是连续存放的,我们可以将这4个字符串看成一个4行16列的二维数组,按照要求,需要修改每一个单词,即二维数组的每一行的前三列。
进行4*3次的二重循环,使用R定位行,变量C定位列。外层循环按行来进行,内层循环按列来进行。过程如下:
-
R=第一行的地址
mov cx,4
S0:C=第一列的地址
mov cx,3
s:改变R行,C列的字母为大写
C=下一列的地址
loop s
R=下一行的地址
loop s0
使用bx来作变量,定位每行的起始地址,用si定位要修改的列,用[bx+si]的方式来对目标单元进行寻址
代码:
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg ends
code segment
start:mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4
s0:mov si,0
mov cx,3
s:mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s
add bx,16
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
这段代码,会陷入死循环,原因是cx的使用,程序是二重循环,但是只用了一个循环计数器,造成在进行内层循环的时候覆盖了外层循环的循环计数值。
在debug这个程序,可以发现是因为cx的错误导致的,但是多用一个计数器又不可能,因为loop指令默认使用cx为循环计数器。所以应该在每次开始内层循环的时候,将外层的cx值保存起来,在执行外层循环的loop指令前,再恢复外层循环的cx数值,可以使用dx来保存。
改进后的代码:
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg ends
code segment
start:mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4
s0:mov dx,cx ;使用dx寄存器来临时保存cx的值
mov si,0
mov cx,3
s:mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s
add bx,16
mov cx,dx ;在这里再恢复cx的值
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
这个程序使用dx来临时保存cx的值,这是可以的,但是有可能dx这个值在内层循环中也会被使用,在这个程序中,si,cx,ax,bx,显然不能存放cx中的数据,因为这些寄存器在循环中也要使用,cs,ip,ds当然也不能使用,因为cs:ip时刻指向当前指令,ds指向datasg段。
所以现在讨论的是,程序中经常需要进行数据的暂存,可能是寄存器中的也可能是内存中的,我们应该怎么样做更为合理。
通用的方案是:使用内存,可以将需要暂存的数据放到内存单元中,需要使用的时候,再从内存单元中恢复,这样就需要开辟一段内存空间。
再改进后的代码:
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
dw 0 ;定义一个字,用来保存cx
datasg ends
code segment
start:mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4
s0:mov ds:[40H],cx ;使用定义的字ds:[40H]来临时保存cx的值
mov si,0
mov cx,3
s:mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s
add bx,16
mov cx,ds:[40H] ;在这里再恢复cx的值
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
多定义一个字,也就是说,使用ds:[40H]来存放cx的值。
但是,上面的方法还是很麻烦,因为如果需要保存多个数据的时候,必须要记住数据存放到了哪个单元,容易混乱,所以更好的方法是使用栈
最终改进的程序:
assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
dw 0 ;定义一个字,用来保存cx
datasg ends
stacksg segment
dw 0,0,0,0,0,0,0,0 ;定义一个栈段,容量为16个字节
stacksg segment
code segment
start:mov ax,stackag
mov ss,ax
mov sp,16
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4
s0:push cx ;使用定义的栈临时保存cx的值
mov si,0
mov cx,3
s:mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc si
loop s
add bx,16
pop cx ;在这里再恢复cx的值
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
7.9问题
问题:[bx+si+idata]的灵活运用
编程,将datasg段中每个单词的前四个字母改为大写字母
assume cs:codesg,ds:datasg,ss:stacksg
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
datasg segment
db '1.display '
db '2.brows '
db '3.replace '
db '4.modify '
datasg ends
code segment
start:......
codesg ends
end start
分析:
其中定义的字符串在内存中的存放是这样的: 3.png由于数据是连续存放的,可以将这四个字符串看作一个4行16列的二维数组,按照要求,需要修改每个单词的前4个字母,即二维数组的每一行的3~6列。需要进行4*4的二重循环,用变量R定位行,常量3定位每行要修改的起始列,变量C定位相对于起始列的要修改的列,
首先使用R定位第一行,循环修改R行的3+C列
然后再用R定位到下一行,再次循环修改R行的3+C列
使用bx来做变量,定位每行的起始地址,用si定位要修改的列,用[bx+3+si]的方式来对目标单元进行寻址。
代码:
assume cs:codesg,ds:datasg,ss:stacksg
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
datasg segment
db '1.display '
db '2.brows '
db '3.replace '
db '4.modify '
datasg ends
code segment
start:mov ax,stacksg
mov ss,ax
mov sp,16 ;让CPU知道和栈段挂钩
mov ax,datasg
mov ds,ax ;让CPU知道和ds挂钩
mov bx,0
mov cx,4
s0:push cx ;用来保存cx的值
mov si,0 ;定义列
mov cx,4
s:mov al,[bx+si+3] ;这里是定位到每个要索引的字母,每行总共有四个字母
and al,11011111b
mov [bx+si+3],al
inc si ;使它指向同一行的下一个字母
loop s
add bx,16
pop cx
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
网友评论