使用汇编实现简单的学生成绩管理并排序,其中排序使用的是冒泡排序
本程序是使用结构体实现的,运行环境为Masm for Windows 集成实验环境 2015
以下为核心代码
结构体的定义,名字占20字节,成绩为字类型数据,主要是为了后面输入输出中的计算方便:
STUDENT STRUC ;结构定义
NAMES DB 20 DUP (?)
SCORE dw ?
STUDENT ENDS
结构体数组的定义:
CNT = 10
CLASS STUDENT CNT DUP(<>)
以下代码中出现的变量:
CN DW 10 ;乘数
COUNT DW ? ;记录人数
REAL_COUNT DW 0 ;此变量值为提示正在输入第几个学生的信息
CHN1 DW 2 ;除数
CHN2 DW 10 ;除数
OPT DB ? ;菜单选项的保存
INSIDE DW ? ;排序时使用到的内循环
OUTSIDE DW ? ;外循环
FIXNUM DW 22
NOWS DW 0 ;记录当前输入信息的地址
RANK DW 0 ;记录当前排名
TEMP1 DB 20 DUP(?)
TEMP2 DB 20 DUP(?)
ERROR DB 'INPUT ERROR!',13,10,'$'
NAME_TIP DB 'Name:$'
SCORE_TIP DB 'Score:$'
INPUT_TIP1 DB 'NO.$'
INPUT_TIP2 DB ' STUDENT',13,10,'$'
CLR DB 13,10,'$'
INPUT_TIP3 DB 'Click any key to continue,ESC to exit',13,10,'$'
OUTPUT_TIP1 DB 'Name',15 DUP(' '),'$'
OUTPUT_TIP2 DB 'Score',5 DUP(' '),'$'
OUTPUT_TIP3 DB 'Rank','$'
BLANK_ONE DB ' $'
ERROR_MENU_TIP DB 'Please input again!',13,10,'$'
两个宏指令分别实现字符串输出的功能,以及不定位数数字的输出
;----宏指令字符串的输出----
PRINTS MACRO STR
MOV AH,9
LEA DX,STR
INT 21H
ENDM
;------宏指令输出不定位数的数字-----
PRINTN MACRO NUM
LOCAL LP1,LP2
XOR CX,CX
MOV AX,NUM
CWD
LP1:
DIV CHN2
PUSH DX
INC CX
CMP AX,0
CWD ;重点!!!!!!!
JNZ LP1
LP2:
POP DX
ADD DL,30H
MOV AH,2
INT 21H
LOOP LP2
ENDM
此次实验中输入成绩与存储成绩是最为关键的地方,因为成绩可以是一位数字,也可以是两位数字,更可以是三位数字,怎样保存一个学生的成绩,怎样判断一个学生的成绩输入结束,就是本次实验的难点。以下代码就是我解决这些问题的具体方法。
NEXT1:
MOV CLASS[BX].NAMES[19],'$'
PUSH BX ;保护BX
LOOP_TIP:
PRINTS SCORE_TIP
XOR DX,DX
XOR BX,BX
LOOP2:
MOV AH,1
INT 21H
CMP AL,0DH ;判断是否为回车退出
JZ STORE
SUB AL,30H
JL ERROR1 ; <0 报错 重新输入
CMP AL, 9
JG ERROR1 ; >9 报错 重新输入
CBW
XCHG AX,BX
MUL CN
ADD BX,AX
JMP LOOP2
ERROR1:
PRINTS ERROR
JMP LOOP_TIP
STORE:
MOV DX,BX
CMP DX,100 ;判断输入的成绩是否有效
JA ERROR1
POP BX
MOV CLASS[BX].SCORE,DX
INC CX ;记录学生人数
PRINTS CLR
PRINTS INPUT_TIP3 ;输出提示
MOV COUNT,CX
ADD BX,FIXNUM
MOV NOWS,BX ;存储下一个学生信息的地址
MOV AH,1
INT 21H
CMP AL,1BH ;判断是否为ESC
JNZ OP1_NEW
此次实验的另一个难点就是排序,我用的是冒泡排序的方法,其中判断大小后怎样调换两个学生的信息是关键。
OP2_NEW:
XOR BX,BX
MOV CX,REAL_COUNT
DEC CX
MOV OUTSIDE,CX ;使学生人数减一后给OUTSIDE
OUT_LOOP:
MOV CX,OUTSIDE
MOV INSIDE,CX
MOV BX,0 ;初始化地址
IN_LOOP:
MOV CX,CLASS[BX].SCORE
ADD BX,FIXNUM
CMP CX,CLASS[BX].SCORE
JL EXCHANGE
;以下为循环条件
DEC INSIDE
CMP INSIDE,0
JG IN_LOOP
DEC OUTSIDE
CMP OUTSIDE,0
JG OUT_LOOP
JMP NEXT
EXCHANGE:
;-----成绩位置交换------
MOV DX,CLASS[BX].SCORE ;把小的数给DX
SUB BX,FIXNUM
MOV CLASS[BX].SCORE,DX ;把DX给原本存大数的位置
ADD BX,FIXNUM
MOV CLASS[BX].SCORE,CX ;把CX给原本存小数的位置
;-----姓名位置交换-------
LEA SI,CLASS[BX].NAMES
LEA DI,TEMP1 ;串操作把小数的名字给临时变量一
MOV CX,20
REP MOVSB
SUB BX,FIXNUM
LEA SI,CLASS[BX].NAMES ;串操作把大数的名字给临时变量二
LEA DI,TEMP2
MOV CX,20
REP MOVSB
LEA SI,TEMP1
LEA DI,CLASS[BX].NAMES
MOV CX,20
REP MOVSB
ADD BX,FIXNUM
LEA SI,TEMP2
LEA DI,CLASS[BX].NAMES
MOV CX,20
REP MOVSB
;以下为循环条件
DEC INSIDE
CMP INSIDE,0
JG IN_LOOP
DEC OUTSIDE
CMP OUTSIDE,0
JG OUT_LOOP
最后的成绩按名次输出就比较简单了,能做到姓名、成绩、名次的清晰划分即可,所以就不在此赘述了。
以下为程序运行图: