21,498
社区成员
发帖
与我相关
我的任务
分享
;-------------------------------------------------------------------------------
; 子 程 序
;-------------------------------------------------------------------------------
;从键盘输入ID
getId proc
push ax
push dx
mov ah,9
mov dx,offset enter_id
int 21h ;输入提示
mov [buf_max],11 ;最多输入10个有效字符
mov dx,offset buf_max
mov ah,0ah
int 21h
pop dx
pop ax
ret
getId endp
;-------------------------------------------------------------------------------
;从键盘输入real_name
getName proc
push ax
mov ah,9
mov dx,offset enter_name
int 21h
mov [buf_max],9
mov dx,offset buf_max
mov ah,0ah
int 21h
pop ax
ret
getName endp
;-------------------------------------------------------------------------------
getScore proc
push ax
mov ah,9
mov dx,offset enter_score
int 21h
mov [buf_max],4
mov dx,offset buf_max
mov ah,0ah
int 21h
pop ax
ret
getScore endp
;-------------------------------------------------------------------------------
;拷贝串
;输入:di = 目标缓冲区首地址
copyString proc
push si
push di
push cx
mov si,offset chars
xor cx,cx
mov cl,count
rep movsb
pop cx
pop di
pop si
ret
copyString endp
;-------------------------------------------------------------------------------
;输入新行
newLine proc
push ax
push dx
mov ah,2
mov dl,0dh
int 21h
mov dl,0ah
int 21h
pop dx
pop ax
ret
newLine endp
;-------------------------------------------------------------------------------
;将十进制串转换为二进制值
;输入:si = 数字串地址
;输出:ax(或者al) = 转换后的数
toBinary proc
push bx
push cx
push dx
push si
xor bx,bx
mov si,offset chars
@@10:
mov al,[si] ;接收一个字符
cmp al,0dh
jz @@20
mov ah,0 ;把AH清0,以配合AL
sub al,'0' ;脱衣
;bx是前n次ax加权累加和,如果要与本次的ax相加,则必须先乘以10
shl bx,1 ;初始值为0,第二次是乘以2
mov dx,bx ;存dx中
mov cl,2 ;
shl bx,cl ;bx * 4 ,但初始为0(这一步是实现上一次的值乘以8)
add bx,dx ;初始0,(再与上一次的二倍相加,完成乘以10的任务)
add bx,ax ;bx初始为ax(再加上这一次)
inc si
jmp @@10
@@20:
mov ax,bx
pop si
pop dx
pop cx
pop bx
ret
toBinary endp
;-------------------------------------------------------------------------------
;显示一个串
;输入:dx = 输出串的首地址
disp_string proc
push ax
mov ah,9
int 21h
pop ax
ret
disp_string endp
;-------------------------------------------------------------------------------
;排序(插入法)
;备注:本子程序是用插入法,根据学生的score,从高分到低分,
;依序将其所在记录的地址插入地址索引表
sort_score proc
push ax
push bx
push si
push di
mov bx,offset students ;bx=记录首地址
mov di,offset sortByScore ;di=地址索引表首地址
mov cx,rec_count ;cx=实际建立的记录数
@@10:
mov al,(STUDENT ptr [bx]).score ;逐一取成绩
call insert ;插入地址索引表
add bx,19 ;每条记录长19字节,指向下一条记录
add di,2 ;地址索引表每个结点占2个字节
loop @@10 ;没扫描完就继续
pop di
pop si
pop bx
pop ax
ret
sort_score endp
;-------------------------------------------------------------------------------
;有序插入(是将记录的地址插入按照score的高低,依序插入地址索引表)
;输入:di = 地址索引表变址(它指向最后一个插入的数据后面的空位置)
; bx = 当前记录首地址
; al = 比较因子(即score)
insert proc
push bx
push dx
push di
mov dx,bx ;dx = bx = 持当前记录地址
@@10:
mov bx,[di-2] ;取出索引结点保存的记录地址给bx
cmp bx,0ffffh ;=0ffffh吗(是0ffffh说明是根插入)
jnz @@20 ;!=0ffffh 说明不是根插入,跳
mov [di],dx ;否则为根插入
jmp @@99 ;退出
@@20:
cmp al,(STUDENT ptr [bx]).score
ja @@30 ;
mov [di],dx ;否则是小于,那就放当前位置
jmp @@99 ;退出
@@30:
mov [di],bx ;索引结点内容后移
sub di,2
jmp @@10
@@99:
pop di
pop dx
pop bx
ret
insert endp
;-------------------------------------------------------------------------------
;子程序:将二进制值转换为十进制数串并输出
;输入:ax=要转换并输出的数
;输出:在屏幕上显示bx中的数
;-------------------------------------------------------------------------------
disp_number proc near
push cx
push ax
push dx
push bx
;mov ax,bx ;把要转换的数赋给ax,作为被除数
mov bx,10 ;着bx作为除数
xor cx,cx ;着cx作为压栈记数器
@@10:
xor dx,dx ;清0,以便配合ax做除法
div bx ;dx:ax / 10
push dx ;余数压栈
inc cx ;记数器记下压栈的次数
cmp ax,0 ;商为0则完成转换
jnz @@10
@@20:
pop dx
add dl,'0' ;30h
mov ah,2h
int 21h
loop @@20
pop bx
pop dx
pop ax
pop cx
ret
disp_number endp
;-------------------------------------------------------------------------------
;询问用户是否继续输入
;输出:为jc跳转设置条件
;
yes_no proc
push dx
push ax
call newLine
mov dx,offset yesno
mov ah,9
int 21h
mov ah,1
int 21h
cmp al,'y'
jz @f
cmp al,'Y'
jz @f
jmp @@20
@@:
clc
jmp @@99
@@20:
stc
@@99:
pop ax
pop dx
ret
yes_no endp
;-------------------------------------------------------------------------------
;输入一个水平制表符
h_tab proc
push ax
push dx
mov ah,2
mov dl,9
int 21h
pop dx
pop ax
ret
h_tab endp
end start
;编写汇编语言源程序实现:从键盘输入一组学生记录,包括:
;(1) 学号: 10个十进制数字字符,如7100410130;
;(2) 姓名: 最多8个英文字母,如;liming;
;(3) 成绩:一字节二进制数,大小在十进制数0-100之间。
;然后将记录按成绩从高到低的顺序排列后显示并保存到C盘根目录下的score.txt文本文件中。
;如输出排序记录:
;7100410130 liming 95
;7100410120 wangwu 90
;7100410145 zhangsan 88
;要求:1. 有友好的输入输出提示;
; 2. 有正确的输入判断;
; 3.采用了子程序;
; 4. 对源代码每行都有注释;
;===============================================================================
.model small
.stack 64
;学生数据结构
STUDENT struc
id db 10 dup(' ')
real_name db 8 dup(' ')
score db 0
STUDENT ends
MAX_COUNT equ 10 ;最多可建立多少学生的记录
;-------------------------------------------------------------------------------
.data
;学生数组:
students STUDENT MAX_COUNT dup(<>)
rec_count dw 0 ;实际输入的记录
flag dw 0ffffh ;与sortbyScore不能分离,它是排序用的标志
sortByScore dw MAX_COUNT dup(0) ;记录指针从高分到低分
;DOS 0AH功能 输入串缓冲区:
buf_max db 11
count db 0
chars db 11 dup(0)
f1 db 'score.txt',0 ;文件名
handle dw ? ;文件句柄
create_error_msg db 0dh,0ah,'create file error!','$'
write_error_msg db 0dh,0ah,'write file error!','$'
enter_id db 0dh,0ah,0dh,0ah,'enter id : $'
enter_name db 0dh,0ah,'enter name : $'
enter_score db 0dh,0ah,'enter score : $'
yesno db 0dh,0ah,'Continue? y=continue n=finish$'
heading db 0dh,0ah,'======================================',0dh,0ah
db 'id',9,9,'name',9,9,'score',0dh,0ah,'$'
;-------------------------------------------------------------------------------
.code
start:
mov ax,@data
mov ds,ax
mov es,ax
mov di,offset students ;di=数组变址
mov cx,MAX_COUNT ;最多可建立的记录数
getNext:
push cx ;保护循环记数器
call getId ;从键盘输入ID
call copyString ;将id串复制进students记录
call getName ;从键盘输入real_name
add di,10 ;调整变址
call copyString ;将name串复制进students记录
call getScore ;从键盘输入score
call toBinary ;转换为二进制数
add di,8 ;调整变址
mov [di],al ;放入students记录
inc rec_count ;记下实际输入的记录数
call yes_no ;询问是否继续录入
jc @f ;如果不再继续就跳出
add di,1 ;调整变址
pop cx ;恢复循环记数器
loop getNext
@@:
;从高分到低分建立记录地址的有序索引
call sort_score
;列表显示输入的记录内容(按score从高分到低分)
call newline ;输出新行
mov dx,offset heading ;输出表头
call disp_string
mov cx,rec_count ;取实际要输入的记录数
mov di,offset sortByScore ;
Again:
push cx ;保存大循环记数器
mov bx,[di] ;从索引表中取当前记录的首地址赋予bx
;输出id
xor si,si ;id串下标
mov ah,2 ;使用DOS输出字符功能
mov cx,10 ;要输出的字符数
nextid:
mov dl,(STUDENT ptr [bx]).id[si]
int 21h
inc si ;调整id的下标
loop nextid
;输出real_name
call h_tab ;输出一个制表符
xor si,si
mov ah,2
mov cx,8
nextname:
mov dl,(STUDENT ptr [bx]).real_name[si]
int 21h
inc si ;id的下标
loop nextname
;输出成绩
call h_tab
mov ah,0
mov al,(STUDENT ptr [bx]).score
call disp_number
call newline
inc di ;索引指针
inc di
pop cx
loop Again
;创建文件:
mov ah,3ch
mov cx,0
mov dx,offset f1
int 21h
jc create_error
mov handle,ax
;写磁盘文件
xor dx,dx
mov ax,19 ;每条记录的长度
mul rec_count ;求总长度
mov cx,ax ;赋予cx作为写盘参数
mov ah,40h
mov bx,[handle]
mov dx,offset students
int 21h
jc write_error
;关闭文件:
mov ah,3eh
mov bx,[handle]
int 21h
exit:
mov ax,4c00h
int 21h
create_error:
mov dx,offset create_error_msg
call disp_string
jmp exit
write_error:
mov dx,offset write_error_msg
call disp_string
jmp exit