汇编语言实验总结

本文深入探讨8086 CPU架构,详细解析其引脚功能、寄存器作用及工作原理。同时,全面介绍Debug工具的安装与使用方法,涵盖DOS与Debug命令,展示如何通过Debug进行内存查询、程序调试与字符输出,适合初学者及进阶读者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于debug的使用、安装 https://blog.youkuaiyun.com/PoorGuy_tn/article/details/80362992

8086cpu芯片引脚。地址引脚(20个),数据引脚(16个)
掌握以下dos命令和debug命令。
DOS命令:CD,DIR,DEL,RENAME,COPY,EDIT,MD,RD(选做)
DEBUG命令: A,D,E,P,R,T,U,G

显示属性字
一个字符在显示缓冲区占用2个字节空间,第一个字节为字符的ASCII码,第二个字节为字符的色彩属性。含义如下:

一个字节有8位 其中可组成为
在这里插入图片描述


对于8086 cpu 来说
1word=16bit
1byte=8bit

寄存器是多少位的一个字就等于多少bit


寄存器

1、段地址寄存器
CS(Code Segment)代码段寄存器
DS(Data Segment)数据段寄存器
ES(Extra Segment)附加段寄存器
SS(Stack Segment)堆栈段寄存器

2、地址寄存器
包括指针Ip(Instruction Pointer)

3、变址寄存器
SP(Stack Pointer)
BP(Base Pointer)
SI(Source Index)
DI(Destination Index)

4、数据寄存器
AH&AL=AX(accumulator)累加寄存器,常用于运算;在乘除等指令中指定用来存放操作数,另外,所有的I/O指令都使用这一寄存器与外界设备传送数据。

BH&BL=BX(base):基址寄存器,常用于地址索引

CH&CL=CX(count):计数寄存器,常用于计数;常用于保存计算值,如在移位指令,循环(loop)和串处理指令中用作隐含的计数器.

DH&DL=DX(data):数据寄存器,常用于数据传递。

5、FLAGS标志寄存器 9个
OF overflow flag 溢出标志 操作数超出机器能表示的范围表示溢出,溢出时为1.

SF sign Flag 符号标志 记录运算结果的符号,结果负时为1.

ZF zero flag 零标志 运算结果等于0时为1,否则为0.

CF carry flag 进位标志 最高有效位产生进位时为1,否则为0.

AF auxiliary carry flag 辅助进位标志 运算时,第3位向第4位产生进位时为1,否则为0.

PF parity flag 奇偶标志 运算结果操作数位为1的个数为偶数个时为1,否则为0.

IF interrupt flag 中断标志 IF=1时,允许CPU响应可屏蔽中断,否则关闭中断.

TF trap flag 陷阱标志 用于调试单步操作.

DF direcion flag 方向标志 用于串处理.DF=1时,每次操作后使SI和DI减小.DF=0时则增大.


内存

00000-9ffff 主存储器
A0000-bffff 显存
C0000-fffff 各类ROM (只读存储器
在这里插入图片描述
外设端口
各种接口芯片中的端口。端口地址64K个。

显存
显存 80*25彩色字符模式显示缓冲区 B8000H 显示缓冲区

偏移000~09f对应显示器上的第一行(80个字符占160个字节)
000~159 刚好一共160个 159B=09f

偏移0AF~13f对应显示器上的第二行
在这里插入图片描述
想在debug框中用-e输出各种字符(及其颜色属性
两种方法:

-e b800:0000 4a 4a 4b 4a //4a为ascii码 4a为颜色属性 后两个同理
-e b800:0000 'J' 4a 'K' 4a

要显示其字符及属性时
-e b800:0000
=>
B800:0000 3A.4a 07.4a 30....

最大段地址FFFF 最小段地址0000

易错
mov [0010],ax:将ax里的值放入16号单元
在最右下角可以看到DS的第16号单元即【0010】已经等于F8H 而F8H正是-8的补码11111000B的十六进制数


首先来看一下如何运行.asm文件
记事本里面写好代码 将扩展名改成.asm

在缓冲区buf中第一个字节里放的是最大定义的字符数,即buf[0],第二个字节是实际输入的字符数,由系统自动填写进去,即buf[1]
有一个难点是想要将缓冲区最后一个字符(本来是OD回车)改成能被识别的’$’字符,首先要获得最后一个字符的偏移地址,需要将实际输入的字符数(buf[1])加上2(前两个字节)

masm a.asm //注意这个文件放在挂载路径里
link a.obj
a.exe 

debug a.exe //调试

data segment //数据段
buf db 20,?,20 dup(?) ;定义一个字符串buf 最大长度20,实际输入的字符数,20个?(算上前面两个共22个字节)
data ends

code segment //代码段
assume cs:code,ds:data //伪指令 指明段寄存器和段的对应关系
start:
	mov ax,data  
	mov ds,ax //将data放入ds
	mov dx,offset buf //将buf的偏移地址放入dx
	mov ah,10 //将键盘输入字符串 调用10号DOS功能
	int 21h //中断

	mov bl,buf[1] //buf[1]里面的值放入bl
	add bl,2 //给bl加2
	mov bh,0//把0放入bh中
	
	mov byte ptr buf[bx],'$' //把$放入buf[bx]
	mov dx,offset buf//把buf的偏移地址放入dx
	mov ah,9//调用9号DOS功能 显示字符串
	int 21h //中断
	
	mov ah,4ch //结束程序
	int 21h
code ends
end start


实例:实现Y=2X+3,X是一位十进制数。要求X从键盘输入,在下一行上显示“Y=2X+3=”以及十进制计算结果。

1)首先定义字符串buf,然后定义变量x=03h(即需要加的3),定义y,这个y是换行的意思,使程序运行起来便于观察
2)先调用1号DOS功能,输入x,再输出y进行换行
3)需要注意的一点是 1、2号DOS功能都是需要更新al里面的值的,所以为了防止输入的x值变成输出的换行的ascii码,先将装有x的Ascii码值放入bl中,然后再输出换行符
4)先把al中的x的ascii码转换成x的数字,对al再加一次相当于将x乘以2,用daa进行调整,再加上变量x中的03h,也就是加3,在输出之前加上30h,转变成ascii码
5)先把buf的短地址和偏移地址分别放入ds、dx中,调用9号DOS功能,输出buf那一串表达式,再把结果输出即可

在这里插入图片描述


实验三:
1.用多种内存查询方式查询2班3号同学的成绩,需要使用debug方式进行,对每一次查询结果进行截图,(例如对mov dx,score[bx][si]那行截图)只截查询结果那一小条就可以。
首先我们定义二维表 数据类型为dw 所以每一个数据占两个字节 如果我们要查第二排的第三个 那么就是 一排有五个同学 而且在地址中都是从0开始的 则第14个地址 即[0eh]就是我们用直接寻址查到的偏移地址 ;寄存器间接寻址同理,只需要把14放入寄存器中,再用[寄存器]表示偏移地址即可 ;寄存器相对寻址则是以二维表初始地址加上第14个 即[score+bx] 或score[bx]; 基址变址寻址 即为 将score表的偏移地址放入寄存器和第14个位置放入变址寄存器SI中,以[bx+si]或[bx][si]查询;相对基址变址寻址则为我们将第一组地址和第二组地址的和14 拆成10 和 4 进行相加,再和score的偏移地址进行相加即可 即score[bx][si]

data segment
score dw 100,98,98,97,95
      dw 100,98,96,95,95
data ends

code segment 
assume cs:code,ds:data 
start:	
	mov ax,data
	mov ds,ax
	
	mov dx,ds:[0eh] ;直接寻址
	
	mov bx,14
	mov dx,[bx] ;寄存器间接寻址
	mov dx,[score+bx] ;寄存器相对寻址

	mov bx,offset score
	mov si,14
	mov dx,[bx][si];基址变址寻址

	mov bx,10
	mov si,4
	mov dx,score[bx][si] ;相对基址变址寻址

	mov ah,4ch
	int 21h
			
code ends
end start

注意:
cn dw ?
mov [cn],ax 是这样用的

换行和回车的区别:

'\r’是回车,前者使光标到行首,(carriage return)

'\n’是换行,后者使光标下移一格,(line feed)

\r 是回车,return

\n 是换行,newline

2.根据学号显示名字截图要求,两个代码,分别是模仿了C语言的二维字符数组和一维字符型指针数组。
(1)执行效果图
(2)两个代码数据段的截图

data segment
	stu 	db 'noting     $'
		db 'zhaodanshi $'
		db 'mizehui    $'
		db 'liruihan   $'
		db 'caoweiqiang$'
	info db 'please input the student number no more than 4:$'
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 ah,1
	int 21h
	sub al,30h
	mov bl,12
	mul bl
	
	mov dx,offset stu
	add dx,ax
	mov ah,9
	int 21h

	mov ah,4ch
	int 21h		
code ends
end start

data segment
	table dw stu0,stu1,stu2,stu3,stu4
	stu0 	db 'noting     $'
	stu1	db 'zhaodanshi $'
	stu2	db 'mizehui    $'
	stu3	db 'liruihan   $'
	stu4	db 'caoweiqiang$'
	info db 'please input the student number no more than 4:$'
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 ah,1
	int 21h
	sub al,30h
	mov bl,2
	mul bl
	
	mov bx,ax
	mov dx,table[bx]
	mov ah,9
	int 21h

	mov ah,4ch
	int 21h		
code ends
end start

#include<stdio.h>
int main(){
	char *stu[5]={"noting","zhaodanshi","mizehui","liruihan","caoweiqiang"};//一位字符型指针数组 好处是可以输出地址
	int d =0;
	printf("%s","Please input the student number no more than 4:");
	scanf("%d",&d);
	printf("%s\n",stu[d]);
	printf("%p\n",stu[d]);//输出地址
	printf("%s\n","Adreess of 0-4");
	printf("%p\n",stu[0]);
	printf("%p\n",stu[1]);
	printf("%p\n",stu[2]);
	printf("%p\n",stu[3]);
	printf("%p\n",stu[4]);
	return 0;
}

查表实验
输入十进制 输出16进制 范围(0~F)
首先定义表table,里面放入对应十六进制符号的ASCII码,分别调用两次1号DOS,输入十位个位,通过xlat进行查找,并输出对应的符号

data segment
	table db 30h,31h,32h,33h,34h,35h,36h,37h
	      db 38h,39h,41h,42h,43h,44h,45h,46h  
	info db 'please input the number you want to dispaly:$'
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 ah,1
	int 21h
	sub al,30h
	mov bl,al

	mov ah,1
	int 21h
	sub al,30h
	mov cl,al

	mov al,bl
	mov dl,10
	mul dl
	add al,cl
	
	mov bx,offset table
	xlat
	
	mov dl,al
	mov ah,02h
	int 21h

	mov ah,4ch
	int 21h		
code ends
end start

输入十进制数0-255,显示相应的十六进制数,用取余数的方法转换。
data segment
n db 4,?,3 dup(?)
a db 16	
x db 100
y db 10
g db ?
s db ?
b db ?
sum dw 0
data ends
code segment 
assume cs:code,ds:data 
start:	
	mov ax,data
	mov ds,ax
	mov dx,offset n
	mov ah,10
	int 21h
	mov cl,n[2]
	mov b,cl
	mov cl,n[3]
	mov s,cl
	mov cl,n[4]
	mov g,cl
	sub b,30h
	sub s,30h
	sub g,30h
	mov dx,0Ah
	mov ah,2
	int 21h
	mov ah,b
	mov al,g
	mov cl,22
	mov ch,0
next:	add al,s
	daa
	dec y
	cmp y,0
	ja next
	mov sum,ax
let:
	cmp ax,9
	ja qiuyu
	mov dx,ax
	add dx,30h
	mov ah,2
	int 21h
	jmp exit
qiuyu:  sbb ax,6
	das
	sbb ax,10
	das
	inc y
	cmp ax,cx
	jae qiuyu
	mov sum,ax
let1:	
	mov bx,sum
	mov bh,y
	cmp bh,9
	ja print1
	jmp print2
	
print1: 
	mov dl,bh
	add dl,31h
	mov ah,2
	int 21h

	cmp bl,9
	ja print3 ;37h
	jmp print4 ;30
print2:
	mov dl,bh
	add dl,30h
	mov ah,2
	int 21h

	cmp bl,9
	ja print3 ;37h
	jmp print4 ;30
print3: 
	mov dl,bl
	add dl,31h
	mov ah,2
	int 21h
	jmp exit
print4:
	mov dl,bl
	add dl,30h
	mov ah,2
	int 21h
	jmp exit
exit:
	mov ah,4ch
	int 21h
code ends
end start

3.模仿课本1195.5.3示例5-9,将以前自己写的程序整理成菜单程序。table表里面保存的是跳转到程序的标号。
data segment
	table dw p0,p1,p3
	mess1 db '0:A->a'
	      db 0ah,'1:a->A'
	      db 0ah,'2:exit$'
data ends
code segment
	assume cs:code,ds:data
start:
	mov ax,data
	mov ds,ax
let0:
	mov dx,offset mess1
	mov ah,9
	int 21h
	
	mov ah,1
	int 21h
	and al,03h
	mov ah,0
	shl ax,1
	mov bx,ax
	jmp table[bx]
	
p0:	
	mov ah,1
	int 21h
	add al,20h
	mov dl,al
	mov ah,2
	int 21h
	jmp let0
p1:
	mov ah,1
	int 21h
	sub al,20h
	mov dl,al
	mov ah,2
	int 21h
	jmp let0
p3:
	mov ah,4ch
	int 21h
	
code ends
end start

实验6:子程序设计
1.完成从键盘输入学生姓名和成绩,按成绩降序排列,并显示排序结果。
(1)代码

data segment
table dw s1,s2,s3
s1 db 10,?,10 dup(?)
s2 db 10,?,10 dup(?)
s3 db 10,?,10 dup(?)
str db 0dh,0ah,'$'
score dw 0,0,0
rank dw 0,1,2
n db 3
grade db 0
data ends
code segment
assume cs:code,ds:data
main proc far
start:
	mov ax,data
	mov ds,ax
	call shuru
	call sort
	call shuchu
	mov ah,4ch
	int 21h
main endp

shuru proc near
	mov bx,0
	mov cl,n
	mov ch,0
	mov dx,0

loop1:
	mov dx,offset table[bx]
	mov ah,10
	int 21h
	
	mov ah,9
	mov dx,offset str
	int 21h

	mov dx,0
	mov ah,1
	int 21h
	mov grade,al

	mov ax,0
	mov ah,1
	int 21h
	mov ah,grade
	mov score[bx],ax

	mov ah,9
	mov dx,offset str
	int 21h
next:	
	inc bl
	inc bl
	loop loop1
	ret
shuru endp		

sort proc near
	mov cx,n
	mov ch,0
	dec cx
loop3:	push cx
	mov bx,0
loop2:	mov ax,score[bx]
	cmp ax,score[bx+2]
	jae next2
	xchg ax,score[bx+2]
	mov score[bx],ax

	mov ax,rank[bx]
	xchg ax,rank[bx+2]
	mov rank[bx],ax

next2: 	add bx,2
	loop loop2
	pop cx
	loop loop3
	ret
sort endp

shuchu proc near
	mov di,0
	mov cx,3
loop4:	mov bx,rank[di]
	add bx,bx
	mov si,offset table[bx]
	mov byte ptr table[si+7],'$'
	add si,2 ;?
	mov dx,si
	mov ah,9
	int 21h

	mov ah,9
	mov dx,offset str
	int 21h

	mov dx,score[di]
	mov ah,2
	int 21h

	mov dx,score[di]
	mov dl,dh
	mov ah,2
	int 21h

	mov ah,9
	mov dx,offset str
	int 21h
	
next3:	add di,2
	loop loop4
	ret
shuchu endp
	
		
code ends
end start

2.用递归完成阶乘运算。
(1)代码

code segment
assume cs:code

main proc far
start:
	mov bx,5
	push bx
	call fac
	mov ah,4ch
	int 21h
main endp

fac proc near
	mov bp,sp
	mov bx,[bp+2]
	cmp bx,1
	ja next
	mov ax,1
	jmp res
next:	
	dec bx
	push bx
	call fac 
	mov bp,sp
	mov bx,[bp+2]
	mul bx
res:
	ret 2
fac endp
	
code ends
end start

在这里插入图片描述
Ss:ffff:00 ——bh
Ss:fffe:05 ——bl
Ss:fffd:00 ——mov ah,4ch 的IP高位
Ss:fffc:07 ——mov ah,4ch 的IP低位
Ss:fffb:00 ——减一后的bh
Ss:fffa:04 ——减一后的bl
Ss:fff9:00 ——第一次进入next里的mov bp,sp 的IP高位
Ss:fff8:20 ——第一次进入next里的mov bp,sp 的IP低位
Ss:fff7:00 ——减一后的bh
Ss:fff6:03 ——减一后的bl
Ss:fff5:00 ——第二次进入next里的mov bp,sp 的IP高位
Ss:fff4:20 ——第二次进入next里的mov bp,sp 的IP低位
Ss:fff3:00 ——减一后的bh
Ss:fff2:02 ——减一后的bl
Ss:fff1:00 ——第三次进入next里的mov bp,sp 的IP高位
Ss:fff0:20 ——第三次进入next里的mov bp,sp 的IP低位
Ss:ffef:00 ——减一后的bh
Ss:ffee:01 ——减一后的bl
Ss:ffed:00 ——第四次进入next里的mov bp,sp 的IP高位
Ss:ffec:20 ——第四次进入next里的mov bp,sp 的IP低位

坑1:想要引用数组下标,括号里必须是立即数,否则视为寄存器间接寻址
坑2:字符串输出是从显示字符串的9号功能里面的偏移地址+1的字符开始输出


在这里插入图片描述
模块的参数设置
(1)Public :将本模块中的符号或者过程定义为全局变量,供其它模块使用。
格式:public 符号1,符号2,符号3
(2)Extrn :引入外部符号或者过程。
Extrn 符号1:类型,符号2:类型
其中类型为byte,word,dword,near,far
(3)参数传递
寄存器传参
存储单元传参
堆栈传参

将每一个子程序拆分出来作为新的asm文件,还要注意子程序里独有的变量定义在自己的asm文件里的数据段中,并把主模块中涉及到子模块的独有的变量定义语句删除
在主模块中,要用extrn定义其他子模块,并且有全局变量时需要用public定义
在子模块中,子程序的属性都要定义为far,最后的标号为end,如果引用了外部变量则需要用extrn 变量名:类型来定义,还需要用public定义自己这个子程序名以调用

main.asm
extrn sname:far,sscore:far,sort:far,pname:far,pscore:far
public table
data segment public 'data'
;输入姓名提示信息
info db 0dh,0ah,'Please input name no more than 14:$'
;输入成绩提示信息
info1 db 0dh,0ah,'Please input score[0-99]:$'
;输入学生个数
n equ 5
;最大允许输入的姓名长度
namec equ 14
;用来存放姓名偏移地址的字表/一维字数组
table dw s0,s1,s2,s3,s4
;s0-s4用来保存输入的姓名 
s0 db namec,?,namec+1 dup('$')
s1 db namec,?,namec+1 dup('$')
s2 db namec,?,namec+1 dup('$')
s3 db namec,?,namec+1 dup('$')
s4 db namec,?,namec+1 dup('$')
;用来存放5个学生的成绩
score dw 5 dup(0)
;用来存放学号的数组
rank dw 0,1,2,3,4
data ends
stack segment stack 'stack'
db 512 dup(?)
stack ends
code segment para 'code'
assume cs:code,ds:data
main proc far
start:
	mov ax,data
	mov ds,ax

	mov cx,5
	mov bx,0 ;学号传递
scans: ;scans是用来输入5个同学姓名和成绩的循环。
	;因为bx是sname子过程的参数,有可能被sname更改,而在之后的程序中又用到了bx,所以进行入栈保存。
	mov dx,offset info
	mov ah,9
	int 21h
	push bx
	call sname ;输入姓名,并且将其保存在正确的位置。
	pop bx

	push bx
	mov dx,offset info1
	mov ah,9
	int 21h
	mov bp,offset score
	call sscore ;输入两位成绩,将其转化为数字,存储到相应位置。
	pop bx

	inc bx ;学号加1
	loop scans 

	mov bx,offset score
	lea bp,rank
	mov ax,n
	call sort ;对学生成绩进行排序
	mov cx,5
	mov di,0
ps:
	mov ax,rank[di]
	call pname ;打印姓名
	mov ax,score[di]
	call pscore ;打印成绩
	add di,2
	loop ps
	mov ah,4ch
	int 21h
main endp
code ends
end start

m1.asm
public sscore
data segment public 'data'
;用来存放输入的成绩,最大允许输入两位
;经测试验证,虽然回车不算到输入字符的个数中,但是最大允许输入的字符个数要算上回车
score1 db 3,?,3 dup('$')
data ends
code segment 'code'
assume cs:code,ds:data
;参数:通过bx传递。学号:0-4 。bp传递成绩数组首地址。
;返回值:无
;功能:成绩输入到相应的字符缓冲区score1中,并转化为十进制数存放到score数组中。
sscore proc far
	push dx
	push ax
	push cx
	push si
	push di 
	mov dx,offset score1
	mov ah,10
	int 21h ;输入成绩
	mov si,dx ;取到输入成绩字符缓冲区首地址
	mov al,[si+1] ;取到实际输入的字符个数
	cmp al,1 ;看实际输入的成绩是一位数成绩,还是两位数成绩
	jne next1
	mov al,[si+2];一位数成绩,取到这一个字符,转化位十进制数。
	sub al,30h
	mov ah,0
	jmp res1
	next1: ;两位数成绩,转化为十进制数。
	mov al,[si+2]
	sub al,30h
	mov cl,10
	mul cl
	mov cl,[si+3]
	sub cl,30h
	mov ch,0
	add ax,cx
	res1:
	add bx,bx
	mov di,bx
	mov ds:[bp][di],ax ;将转换好的成绩存到数组中
	pop di
	pop si
	pop cx
	pop ax
	pop dx
	ret
sscore endp 
code ends
end 

m2.asm
extrn table:word
public sname
code segment 'code'
assume cs:code
;参数:通过bx传递。学号:0-4 
;返回值:无
;功能:名字输入到指定的字符串缓冲区
sname proc far
	push dx
	push ax
	push si
	add bx,bx
	mov dx,table[bx]
	mov ah,10
	int 21h
	mov bx,dx
	mov al,[bx+1]
	mov ah,0
	add ax,2
	add ax,bx ;算到回车算在的位置,将其改为空格。否则输出姓名用到这个字符串,回车会让光标回到本行起始位置。会影响成绩的输出。
	mov si,ax
	mov byte ptr[si],20h;将回车替换为空格
	mov byte ptr[bx],0dh ;将输入缓冲区的前两个字节换为回车换行
	mov byte ptr[bx+1],0ah
	pop si
	pop ax
	pop dx
	ret
sname endp
code ends
end 

m3.asm
extrn table:word
public pname
code segment 'code'
assume cs:code
;参数 ax:学号
;返回值:无
;功能:输出给定学号学生的姓名
pname proc far
	push bx
	push dx
	add ax,ax ;找到姓名偏移地址值 在 table 表中的偏移位置
    	mov bx,ax
    	mov dx,[table+bx]
    	mov ah,9
    	int 21h
	pop dx
	pop bx
	ret
pname endp
code ends
end 

m4.asm
public sort
code segment 'code'
assume cs:code
sort proc far
	push cx
	push si  
	mov cx,ax
	dec cx
	outs:
	push cx
	mov si,0
	ins:
	mov ax,[bx][si]
	cmp ax,[bx][si+2]
	ja next
	xchg ax,[bx][si+2]
	mov [bx][si],ax
	mov ax,ds:[bp][si]
	xchg ax,ds:[bp][si+2]
	mov ds:[bp][si],ax
	next:
	add si,2
	loop ins
	pop cx
	loop outs
	pop si
	pop cx
	ret 
sort endp
code ends
end 

m5.asm
public pscore
data segment public 'data'
x db ?,?
data ends
code segment para 'code'
assume cs:code,ds:data
;参数 ax:要输出的十进制数字
;返回值:无
;功能:将ax中的数字以十进制的方式输出。
pscore proc far
	push bx
	push dx
	mov bl,10
	div bl
	mov x[0],al
	mov x[1],ah
	add al,30h
	mov dl,al
	mov ah,2
	int 21h
	mov al,x[1]
	add al,30h
	mov dl,al
	mov ah,2
	int 21h
	mov dl,20h
	mov ah,2
	int 21h	
	pop dx
	pop bx
	ret
pscore endp
code ends
end 

a.mac
output macro str
mov dx,offset str
mov ah,9
int 21h
endm

input macro str
mov dx,offset str
mov ah,10
int 21h ;
endm

outc macro c
mov dl,c
mov ah,2
int 21h
endm


main.asm
include a.mac
extrn sname:far,sscore:far,sort:far,pname:far,pscore:far
public table
data segment public 'data'
;输入姓名提示信息
info db 0dh,0ah,'Please input name no more than 14:$'
;输入成绩提示信息
info1 db 0dh,0ah,'Please input score[0-99]:$'
;输入学生个数
n equ 5
;最大允许输入的姓名长度
namec equ 14
;用来存放姓名偏移地址的字表/一维字数组
table dw s0,s1,s2,s3,s4
;s0-s4用来保存输入的姓名 
s0 db namec,?,namec+1 dup('$')
s1 db namec,?,namec+1 dup('$')
s2 db namec,?,namec+1 dup('$')
s3 db namec,?,namec+1 dup('$')
s4 db namec,?,namec+1 dup('$')
;用来存放5个学生的成绩
score dw 5 dup(0)
;用来存放学号的数组
rank dw 0,1,2,3,4
data ends

stack segment stack 'stack'
db 512 dup(?)
stack ends
code segment para 'code'
assume cs:code,ds:data
main proc far
	start:
	mov ax,data
	mov ds,ax

	mov cx,5
	mov bx,0 ;学号传递
	scans: ;scans是用来输入5个同学姓名和成绩的循环。
	;因为bx是sname子过程的参数,有可能被sname更改,而在之后的程序中又用到了bx,所以进行入栈保存。
	output info
	push bx
	call sname ;输入姓名,并且将其保存在正确的位置。
	pop bx

	push bx
	output info1
	mov bp,offset score
	call sscore ;输入两位成绩,将其转化为数字,存储到相应位置。
	pop bx

	inc bx ;学号加1
	loop scans 

	mov bx,offset score
	lea bp,rank
	mov ax,n
	call sort ;对学生成绩进行排序
	mov cx,5
	mov di,0
	ps:
	mov ax,rank[di]
	call pname ;打印姓名
	mov ax,score[di]
	call pscore ;打印成绩
	add di,2
	loop ps
	mov ah,4ch
	int 21h
main endp
code ends
end start

m1.asm
include a.mac
public sscore
data segment public 'data'
;用来存放输入的成绩,最大允许输入两位
;经测试验证,虽然回车不算到输入字符的个数中,但是最大允许输入的字符个数要算上回车
score1 db 3,?,3 dup('$')
data ends
code segment 'code'
assume cs:code,ds:data
;参数:通过bx传递。学号:0-4 。bp传递成绩数组首地址。
;返回值:无
;功能:成绩输入到相应的字符缓冲区score1中,并转化为十进制数存放到score数组中。
sscore proc far
	push dx
	push ax
	push cx
	push si
	push di 
	input score1
	mov si,dx ;取到输入成绩字符缓冲区首地址
	mov al,[si+1] ;取到实际输入的字符个数
	cmp al,1 ;看实际输入的成绩是一位数成绩,还是两位数成绩
	jne next1
	mov al,[si+2];一位数成绩,取到这一个字符,转化位十进制数。
	sub al,30h
	mov ah,0
	jmp res1
	next1: ;两位数成绩,转化为十进制数。
	mov al,[si+2]
	sub al,30h
	mov cl,10
	mul cl
	mov cl,[si+3]
	sub cl,30h
	mov ch,0
	add ax,cx
	res1:
	add bx,bx
	mov di,bx
	mov ds:[bp][di],ax ;将转换好的成绩存到数组中
	pop di
	pop si
	pop cx
	pop ax
	pop dx
	ret
sscore endp 
code ends
end 

m2.asm
include a.mac
extrn table:word
public sname
code segment 'code'
assume cs:code
;参数:通过bx传递。学号:0-4 
;返回值:无
;功能:名字输入到指定的字符串缓冲区
sname proc far
	push dx
	push ax
	push si
	add bx,bx
	input table[bx]
	mov bx,dx
	mov al,[bx+1]
	mov ah,0
	add ax,2
	add ax,bx ;算到回车算在的位置,将其改为空格。否则输出姓名用到这个字符串,回车会让光标回到本行起始位置。会影响成绩的输出。
	mov si,ax
	mov byte ptr[si],20h;将回车替换为空格
	mov byte ptr[bx],0dh ;将输入缓冲区的前两个字节换为回车换行
	mov byte ptr[bx+1],0ah
	pop si
	pop ax
	pop dx
	ret
sname endp
code ends
end 

m3.asm
include a.mac
extrn table:word
public pname
code segment 'code'
assume cs:code
;参数 ax:学号
;返回值:无
;功能:输出给定学号学生的姓名
pname proc far
	push bx
	push dx
	add ax,ax ;找到姓名偏移地址值 在 table 表中的偏移位置
    	mov bx,ax
    	output [table+bx]
	pop dx
	pop bx
	ret
pname endp
code ends
end 

m4.asm
public sort
code segment 'code'
assume cs:code
sort proc far
	push cx
	push si  
	mov cx,ax
	dec cx
	outs:
	push cx
	mov si,0
	ins:
	mov ax,[bx][si]
	cmp ax,[bx][si+2]
	ja next
	xchg ax,[bx][si+2]
	mov [bx][si],ax
	mov ax,ds:[bp][si]
	xchg ax,ds:[bp][si+2]
	mov ds:[bp][si],ax
	next:
	add si,2
	loop ins
	pop cx
	loop outs
	pop si
	pop cx
	ret 
sort endp
code ends
end 

m5.asm
include a.mac
public pscore
data segment public 'data'
x db ?,?
data ends
code segment para 'code'
assume cs:code,ds:data
;参数 ax:要输出的十进制数字
;返回值:无
;功能:将ax中的数字以十进制的方式输出。
pscore proc far
	push bx
	push dx
	mov bl,10
	div bl
	mov x[0],al
	mov x[1],ah
	add al,30h
	outc al
	mov al,x[1]
	add al,30h
	outc al
	outc 20h
	pop dx
	pop bx
	ret
pscore endp
code ends
end 

link main=m1+....+m5
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七灵微

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值