汇编实验小记(五)-循环程序设计

  • 两种循环结构
    • 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,则向下执行其余程序代码bash

ZF-零标志

  • 1:ZR
  • 0:NZ

还未查找到负数的时候:oop

找到负数:spa

3.一、 查找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

交换两个操做数的数据debug

;每一趟冒泡排序都会将最小的浮到最下面
;指向最后一个数,和倒数第二个数进行比较--比较系数在自减
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
复制代码

单步查看每一次排序后的结果3d

初始数据:t1 db 5,6,1,7,4,3,2调试

【注意⚠️】

刚开始进入的是小循环后,就一直t.....t到第二次小循环的loop ,而后再 p dcode

  • 第一次遇到的是小循环,第二次遇到的大循环
相关文章
相关标签/搜索