- 两种循环结构
- DO WHILE的循环结构用CMP指令和条件转移指令构成
- while少用
- 循环指令:loop,loope,loopne
- 伪指令 EQU 及操作符 '$'的使用
- 多重循环中,可以由内层循环向外层循环跳转,或者直接向外层程序跳转,但是不允许从外向内跳转
- 会用循环实现排序算法
1.写出y=5!的程序段
loop指令
cpu执行loop指令的时候,要进行两步操作
LOOP Lable
- (cx)=(cx)-1
- 判断cx中的值,不为零则转至Lable执行,如果为零,则向下执行
data segment
t db '0123456789ABCDEF'
info db 'y = 5! $'
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov dx,offset info
mov ah,9
int 21h
mov al,1 ;起始值:用于储存乘积
mov bl,2 ;乘数起始值
mov cx,4 ; 2*3*4*5 总共进行4次乘法运算->循环次数
s:
mul bl ;5!=120 8位二进制足以表示,所以可以放在al中,就不用ax了
inc bl
loop s
mov bp,4 ;输出为4位数的16进制,所以需要输出4次
s1: ;将结果按照16进制数输出
mov cl,4 ;右移位数
rol ax,cl
mov si,ax
and ax,0fh
mov bx,ax
mov dl,t[bx] ;找到对应的16进制数并输出
mov ah,2
int 21h
mov ax,si ;每次在右移之前就先保存
dec bp
jnz s1 ;bp不为0说明4位数还没有输出够,所以继续
mov ah,4ch
int 21h
code ends
end start
2.查找出数组中的负数,并显示位置id(起始位置从0开始)
1.LOOPZ/LOOPE指令
cpu执行loopz指令的时候,要进行两步操作
LOOPZ/LOOPE Lable
- (cx)=(cx)-1
- 若CX!=0并且同时ZF=1 则转至Lable执行,如果为零,则向下执行
2.ZF--零标志,稍后看debug中分步执行
本题使用:【⚠️栈-保存数据】
data segment
t1 db 1,2,3,4,-5,255,127
t db '0123456789ABCDEF' ;用于二进制计算后对应过来找16进制数
info db 0dh,0ah,'the id of first negtuve number is : $'
count equ $-t1
data ends
stack segment
db 512 dup(?) ;使用栈段
stack ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
mov sp,512
mov dx,offset info
mov ah,9
int 21h
mov bx,0
mov cx,count ;循环中每次自动(cx)=(cx)-1
s:
mov al,t1[bx]
inc bx
and al,80h
loopz s ;判断cx中的值,不为零则转至标号处执行,如果为零,则向下执行
dec bx ;由于上面的循环中s进行了自增,我们需要的指示数是从0开始,所以需要减1
mov ax,bx
mov cx,4 ;转化成4位的十六进制数进行输出
s1:
push cx
mov cl,4
rol ax,cl
mov si,ax
and ax,0fh
mov bx,ax
mov dl,t[bx]
mov ah,2
int 21h
mov ax,si
pop cx
loop s1
add si,2
mov ah,4ch
int 21h
code ends
end start
分步调试看loopz的用法标尺-ZF
若CX!=0并且同时 ZR 则转至Lable执行(继续循环),如果为NZ,则向下执行其他程序代码
ZF-零标志
- 1:ZR
- 0:NZ
还未查找到负数的时候:
找到负数:
3.1、 查找CATI表中的字符@,找到后,输出其所在位置
data segment
t1 db '1234567890@sdfghj'
t db '0123456789ABCDEF' ;用于二进制计算后对应过来找16进制数
info db 0dh,0ah,'the id of @ is : $'
count equ $-t1
data ends
stack segment
db 512 dup(?)
stack ends
code segment
assume cs:code,ds:data,es:data
start:
mov ax,data
mov ds,ax
mov es,ax
mov ax,stack
mov ss,ax
mov sp,512
mov dx,offset info ;提示信息
mov ah,9
int 21h
mov al,'@'
mov di,offset t1 ;取数组t1的首地址到di寄存器中
mov cx,count
cld ;clear df 将方向标志位DF清零 课本20页 0-up,1-down,一直向右
repne scasb ;找到与al相同的数就退出扫描 一直重复搜索到t1字符串末尾 课本134
;但存在问题:此时,cx没有减为0,但是di已经增加1,所以下面需要减1
; 注意:在扫描时,他是先进行di所在位置的数进行比较,无论相等还是不想等,他都会自动执行di+1
dec di ;由于上面的循环中s进行了自增,相等了跳出,但此时di多加了1,想要的到我们的数就需要减1
mov ax,di
mov cx,4
s1:
push cx
mov cl,4 ;由于这里会改变cx的值,所以在上面需要先将cx入栈进行储存
rol ax,cl
mov si,ax
and ax,0fh
mov bx,ax
mov dl,t[bx]
mov ah,2
int 21h
mov ax,si
pop cx
loop s1 ;每次执行完
add si,2
mov ah,4ch
int 21h
code ends
end start
4.冒泡排序
1.jae (cf-进位标志)
- 转移条件:cf=0
- 用于无符号
- 大于或等则跳转
2.cmp
- cmp eax, ebx (eax - ebx = 03h)
- 不保存结果,只是根据结果修改相应的标志位
3.xchg
交换两个操作数的数据
;每一趟冒泡排序都会将最小的浮到最下面
;指向最后一个数,和倒数第二个数进行比较--比较系数在自减
data segment
t1 db 5,6,1,7,4,3,2
count equ $-t1
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov cx,count
dec cx
bubble:
push cx
mov bx,count
dec bx
change:
mov al,t1[bx]
cmp al,t1[bx-1]
jae next ;满足条件 -> next; jae转移条件:cf=0 大于等于 -> 转移
xchg al,t1[bx-1] ;不满足条件 (小于)则进行交换
mov t1[bx],al
next:
dec bx
loop change
pop cx
loop bubble
mov ah,4ch
int 21h
code ends
end start
单步查看每一次排序后的结果
初始数据:t1 db 5,6,1,7,4,3,2
【注意⚠️】
刚开始进入的是小循环后,就一直t.....t到第二次小循环的loop ,然后再 p d
- 第一次遇到的是小循环,第二次遇到的大循环