- 兩種迴圈結構
- 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
- 第一次遇到的是小迴圈,第二次遇到的大迴圈