汇编语言综合大实验,实现学生成绩
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
主要完成5个功能
DATAS SEGMENT HINT_1 DB "please input password:",0AH,0DH,'$' HINT_2 DB "password wrong !",0AH,0DH,'$' HINT_3 DB "three times !",0AH,0DH,'$' HINT_4 DB "password success !",0AH,0DH,'$' HINT_5 DB "error,please input a number !",0AH,0DH,'$' HINT_6 DB "please input the grade:",0AH,0DH,'$' HINT_7 DB "GRADE SUCCESS !",0AH,0DH,'$' HINT_8 DB "number of failed:",0AH,0DH,'$' HINT_9 DB "the average grade is:",0AH,0DH,'$' HINT_10 DB "PLEASE CHOOSE:",0AH,0DH,"3.SORT",0AH,0DH,"4.FAILED",0AH,0DH,"5.AVERAGE",0AH,0DH,"6.EXIT",0AH,0DH,'$' COUNT_1 DB 3;最大输入次数 COUNT_2 DW 6;密码的个数 COUNT_3 DW 35;班级同学人数 COUNT_4 DW 68;用于记录人数在内存中最后的下标,即COUNT_3*2-2 COUNT_5 DW 0;用于记录不及格的人数 COUNT_6 DW 3;保留3位小数 COUNT_7 DW ?;记录用户输入的密码个数 PASSWORD DB "111111" STRING DB 20 DUP(0) CRLF DB 0AH,0DH,'$' N DW ? NUM DW 0;存储当前字符 FLAG_1 DB 0;0代表不是数字,1代表是数字 GRADE DW 35 DUP(0);存储35个学生成绩 ;GRADE DW 2,4,3,7 TEN DW 10 SIXTY DW 60;及格分 INDEX DW 0 AVERAGE DW 0 CHOOSE DB ?;用户输入的选择 DATAS ENDS STACKS SEGMENT PARA STACK DW 20H DUP(0) ;此处输入堆栈段代码 STACKS ENDS
设置默认密码为“111111”。每输入一个密码将其以“*”显示在显示屏上,输入结束后将其与默认密码进行比较,若不相同,则提示重新输入,当输入密码错误3次,则结束程序,若密码输入正确,则进入功能2。具体代码如下:
;密码输入与检测 LOP1 PROC CMP COUNT_1,0;如果输入了三次错误密码,则结束程序 JZ END1 DEC COUNT_1 MOV SI,0 MOV BX,COUNT_2 MOV COUNT_7,0 INITIAL:;初始化,将数组元素置为0 MOV STRING[SI],0 INC SI DEC BX CMP BX,0 JNZ INITIAL MOV SI,0 MOV DX,OFFSET HINT_1 MOV AH,09H INT 21H ;输入密码 INPUTPASSWORD: MOV AL,0 MOV AH,08H INT 21H CMP AL,0DH;判断是否为回车,是的话说明输入结束 JZ CHECK MOV STRING[SI],AL INC SI INC COUNT_7 MOV DL,'*' MOV AH,02H INT 21H JMP INPUTPASSWORD ;检测密码输入是否正确 CHECK: LEA DX,CRLF;输出换行 MOV AH,09H INT 21H MOV CX,COUNT_7 CMP COUNT_2,CX JNZ CONTINUE;密码个数不对,密码错误 MOV DI,OFFSET STRING MOV SI,OFFSET PASSWORD CLD REPZ CMPSB JZ SUCCESS;密码正确 CONTINUE: MOV DX,OFFSET HINT_2 MOV AH,09H INT 21H JMP LOP1 ;密码错误三次,结束程序 END1: MOV DX,OFFSET HINT_3 MOV AH,09H INT 21H MOV AH,4CH INT 21H SUCCESS: LEA DX,HINT_4 MOV AH,09H INT 21H RET LOP1 ENDP
每输入一个数字就将其与之前获得的数字乘10再相加,当遇到空格时,表示一个数据输入成功,此时将其存入到成绩数组中,当输入的字符不是数字时,提示用户输入非法并让用户重新输入该数据。
;键盘输入全班同学总成绩 LOP2 PROC MOV CX,0 MOV SI,0 LEA DX,HINT_6 MOV AH,09H INT 21H INPUT: ;CMP CX,0 ;JZ END2;当输入完35个数字后结束输入 MOV AH,01H INT 21H CMP AL,0DH;遇到回车说明一个数据输入完成 JZ SAVENUM ;JZ END2 CMP AL,' ';遇到空格说明一个数据输入完成 JZ SAVENUM; MOV DL,AL MOV DH,0 PUSH DI PUSH DX CALL ISDIGITAL POP DX POP DI CMP FLAG_1,0;如果不是数字,则要求重新输入 JZ INPUT ;MOV NUM,0 MOV N,DX SUB N,30H MOV AX,NUM MUL TEN ADD AX,N MOV NUM,AX JMP INPUT ;存储输入的成绩 SAVENUM: INC CX MOV BX,NUM MOV GRADE[SI],BX MOV NUM,0 ADD SI,2 CMP AL,0DH;如果输入的是回车,则结束输入 JZ END2 JMP INPUT ;输入完成 END2: MOV COUNT_3,CX LEA DX,HINT_7 MOV AH,09H INT 21H RET LOP2 ENDP ;判断输入的是否为数字字符 ISDIGITAL PROC MOV BP,SP MOV DI,[BP+2] ISBIGGER:;如果0更大的话就跳到非数字 CMP DI,'0' JB NONDIGITAL ISSMALL:;如果9更大的话就跳到数字 CMP DI,'9' JBE DIGITAL JMP NONDIGITAL NONDIGITAL: MOV FLAG_1,0 CALL OUTPUTCRLF LEA DX,HINT_5 MOV NUM,0;将缓存的数据清零 MOV AH,09H INT 21H RET DIGITAL: MOV FLAG_1,1 RET ISDIGITAL ENDP
用冒泡排序对所有成绩进行从大到小的排序,然后调用将二进制转换为十进制的子程序将每个数据转换为其对应的ASCII码显示到屏幕上。
;从高到低排名 LOP3 PROC MOV CX,0 FIRST: MOV DI,0 INC CX CMP CX,COUNT_3 JZ OUTPUT_3 COMPARE: MOV BX,GRADE[DI] CMP BX,GRADE[DI+2] JB SWAP RETURN1: ADD DI,2 CMP COUNT_4,DI JZ FIRST JMP COMPARE SWAP:;交换 MOV AX,GRADE[DI+2] MOV GRADE[DI],AX MOV GRADE[DI+2],BX JMP RETURN1 OUTPUT_3:;比较结束 MOV CX,COUNT_3 MOV SI,0 OUTPUT0: MOV AX,GRADE[SI] PUSH AX CALL OUTPUT CALL OUTPUTSPACE ADD SI,2 DEC CX CMP CX,0 JNZ OUTPUT0 CALL OUTPUTCRLF RET LOP3 ENDP
其流程图如下:
遍历成绩数组,用一个计数器存储不及格人数,初值为0,当该成绩小于60时,计数器加1,遍历结束后,调用将二进制转换为10进制的子程序输出该结果。
;输出不及格的人数 LOP4 PROC MOV COUNT_5,0 MOV SI,0 MOV CX,0 COMPARE2: MOV BX,SIXTY CMP GRADE[SI],BX JB ACCOUNT RETURN2: ADD SI,2 INC CX CMP CX,COUNT_3 JNZ COMPARE2 JZ END4 ;不及格人数加1 ACCOUNT: INC COUNT_5 JMP RETURN2 END4: ;输出不及格人数 LEA DX,HINT_8 MOV AH,09H INT 21H MOV AX,COUNT_5 PUSH AX CALL OUTPUT CALL OUTPUTCRLF RET LOP4 ENDP
遍历成绩数组,将每个成绩相加,结果存入AX寄存器中,将AX寄存器中的数值除以总人数,获得商,并将其输出,再将余数乘以10除以总人数,获得第一位小数,以此类推,循环3次后,输出小数部分。
;求平均成绩 LOP5 PROC MOV SI,0 MOV CX,COUNT_3 DEC CX MOV BX,GRADE[SI] ADD AVERAGE,BX ADDSUM: ADD SI,2 MOV BX,GRADE[SI] ADC AVERAGE,BX LOOP ADDSUM LEA DX,HINT_9 MOV AH,09H INT 21H MOV AX,AVERAGE CWD DIV COUNT_3 PUSH DX;保护余数 PUSH AX CALL OUTPUT MOV DX,'.' MOV AH,02H INT 21H MOV CX,COUNT_6 POP AX ;小数的处理 DECIMAL: MUL TEN CWD DIV COUNT_3 PUSH DX;保护余数 PUSH AX;输出商 CALL OUTPUT POP AX;余数继续乘10再除以除数 LOOP DECIMAL CALL OUTPUTCRLF RET LOP5 ENDP
在调用前需要先将想输出的二进制数存入栈中,然后在子程序里令AX等于BP+2的值,令INDEX等于0,当AX不等于0时,将AX除以班级人数,将余数加上30H后入栈,同时INDEX加1,当AX等于0时,输出栈里的数据,最后结束子程序时将一开始进栈的二进制数一起弹出栈。
;二进制转十进制的输出子程序,要将想输出的数据压入栈,改变了AX,DX OUTPUT PROC MOV BP,SP MOV AX,[BP+2] MOV INDEX,0 OUTPUT2: CWD DIV TEN ADD DX,30H PUSH DX INC INDEX CMP AX,0 JZ OUTPUT3 JMP OUTPUT2 OUTPUT3: CMP INDEX,0 JZ OUTPUTEND POP DX MOV AH,02H INT 21H DEC INDEX JMP OUTPUT3 OUTPUTEND: RET 2 OUTPUT ENDP ;输出空格 OUTPUTSPACE PROC MOV DX,20H MOV AH,02H INT 21H RET OUTPUTSPACE ENDP ;输出换行 OUTPUTCRLF PROC LEA DX,CRLF MOV AH,09H INT 21H RET OUTPUTCRLF ENDP
先调用功能1子程序,再调用功能2子程序,然后输出菜单供用户选择,当用户输入3时,调用功能3子程序,输入4时,调用功能4子程序,输入5时,调用功能5子程序,直到输入6时,结束程序。
;主程序 MAIN: CALL LOP1 CALL LOP2 LEA DX,HINT_10 MOV AH,09H INT 21H SETCHOOSE: MOV AH,01H INT 21H MOV CHOOSE,AL CALL OUTPUTCRLF CMP CHOOSE,'3' JZ CALL3 CMP CHOOSE,'4' JZ CALL4 CMP CHOOSE,'5' JZ CALL5 CMP CHOOSE,'6' JZ ENDMAIN JNZ SETCHOOSE CALL3: CALL LOP3 JMP SETCHOOSE CALL4: CALL LOP4 JMP SETCHOOSE CALL5: CALL LOP5 JMP SETCHOOSE
本次实验主要练习了子程序的使用和各种传参方式,是一个比较考验汇编编程综合能力的实验。