实验四 子程序设计
一、实验目的
1. 进一步掌握子程序设计方法; 2. 进一步掌握基本的 DOS 功能调用。
二、实验内容
1. 从键盘上输入某班学生某科目成绩,输入按学生的学号由小到大的顺序输入。 2. 统计检查每个学生的名次。 3. 将统计结果在屏幕上显示。
4. 为便于观察,输入学生数目不宜太多,以不超过一屏为宜。输出应便于阅读。
尽可能考虑美观。 5. 输入要有检错手段。
三、预习思考
1. 如何确定一个学生在这门科目中的名次?
? 抽取每个学生的成绩和其他所有学生的成绩进行比较,然后统计比其分数高的学
生,得出该学生的名次
? 把学生成绩以数组方式进行存储,取得每个学生的成绩指针。然后比较指针所指
的成绩的大小,根据比较结果移动指针完成排序。排序方法有多种:冒泡法,快速排序法、归并排序法等。
2. 输入结束后,采用什么方法进行比较以得到学生的名次最为简单?
? 冒泡法平均时间性能O(N),快速排序、归并排序等优化的算法的时间复杂度
O(N*log2N),虽然后两者的时间复杂度较小,但汇编中的代码复杂度和编程要求都比较高。由于本实验要求的学生人数比较少,故采用冒泡排序法,时间性能不是很差,代码比较简洁,较好的协调了时间和空间性能。 3. 准备好模块层次图。
? 见第四部分框图中的模块层次图
4. 给出输出显示的形式。
? 输出形式具体可见代码的DATA部分,或者程序运行结果截图。
2
四、框图
流程图:
开始读取用户输入的数据调用获取学生人数的子程序获取分数的指针偏移量打印错误提示输入合法?调用冒泡排序的子程序采用冒泡排序法排序指针判断用户输入的是学号还是成绩调用打印学号、分数、排名的子程序根据排序结果写入学生的名次将学号、分数分别写入内存区结束
模块层次图:
主程序 MAIN PROC获取学生人数GETNUMBER PROC获取字符串GETIN PROC合法性检测CHECK PROC 显示PRINT PROC打印错误信息PRINTERR PROC
冒泡排序SORT PROC获取字符串GETIN PROC合法性检测CHECK PROC 获取学号和分数处理成绩GETINFO PROCCHANGE PROC 五、源代码
DATA SEGMENT ID DB 400 DUP(?) ;存储学号,每个16固定个BYTE,存储为字符串 MARK DB 20 DUP(?) ;存储分数,每个1BYTE,存储为二进制数 RANK DB 20 DUP(?) ;存储排名,每个1BYTE,存储为二进制数 RANKTMP DB 20 DUP(?);排序时指针临时区 MTMP DB ? ;记录成绩的临时区 COUNTB DB ? ;记录总的学生的个数,存为8位 COUNTW DW ? ;记录总的学生个数,存为16位
CHEOK DB ? ;输入检查标志位 ERROR1 DB ? ;记录错误号 TMP DB 2 DUP(?) ;开辟两个内存临时存储区,用作判断和计数 CR DB 0DH,0AH,'$' ;回车换行 TAB DB 09H,09H,'$' ;输出TAB键 ERR0 DB 'Input cannot be empty!','$' ERR2 DB 'Character is invalid!','$' ERR4 DB 'Mark is invalid!','$' ERR6 DB 'Input is invalid!','$' ERRLIST DW ERR0,ERR2,ERR4,ERR6 TIP0 DB 'Please re-input:','$' TIP1 DB 'Please input number of students:','$' TIP2 DB 'Please input ID and MARK:','$' PRTIP DB '--------------RESULT---------------','$' PRINFO DB 'ID',09H,09H,'MARK',09H,09H,'RANK','$' PRPRE1 DB 'ID : ','$' PRPRE2 DB 'MARK: ','$' BUFF DB 16 ;定义输入缓冲区,最长的字符长度 PRES DB ? ;存储实际输入了多少个字符 CHAR DB 16 DUP(?) ;实际可存储有效字符16个 DATA ENDS CODE SEGMENT ;-------------------------------------------------------- ;打印提示字信息的宏,形参为PARA PRINTTIP MACRO PARA PUSH AX PUSH DX MOV AH,09H MOV DX,OFFSET PARA INT 21H POP DX POP AX ENDM
;-------------------------------------------------------- ;打印单个字符的宏,形参为ACHAR PRINTCHAR MACRO ACHAR PUSH AX PUSH DX MOV AH,02H MOV DL,ACHAR INT 21H POP DX POP AX ENDM ;-------------------------------------------------------- ;主程序 MAIN PROC FAR ASSUME CS:CODE,DS:DATA,ES:DATA ;分别建立对应关系 MOV AX,DATA MOV DS,AX ;给数据段段基址赋初值 MOV ES,AX ;给附加数据段段基址赋初值 CALL GETNUMBER ;获得学生的人数 CALL GETINFO ;获得学号分数的输入 CALL SORT ;执行排序活动名次 CALL PRINT ;把名次结果打印出来 BACK: MOV AX,4C00H ;返回DOS INT 21H MAIN ENDP ;-------------------------------------------------------- ;获得将要输入的学生的人数信息的子程序 ;每班的学生定义不超过100人 GETNUMBER PROC NEAR ;定义近过程 PUSH AX ;保护现场 PUSH BX PRINTTIP TIP1 HE: GREP: CALL GETIN ;获取一个输入缓冲
MOV CHEOK,0 CALL CHECK ;检测输入是否合法 CMP CHEOK,0 ;和0进行比较 JE GRETURN ;如果为0说明输入没有错误,获取输入的数字 MOV ERROR1,6 ;如果不合法则打印错误提示信息 CALL PRINTERR ;打印输出错误 PRINTTIP TIP0 ;打印重输入提示消息 PRINTTIP CR ;回车换行 JMP GREP ERRHERE:PRINTTIP CR ;打印回车换行 MOV ERROR1,6 ;移入错误类型 CALL PRINTERR ;打印错误 PRINTTIP TIP0 ;打印重输入提示消息 JMP GREP GRETURN:CALL CHANGE ;调用子程序处理输入的数据 MOV AL,MTMP ;将MTMP中的值移入AL CMP AL,0 ;与0进行比较 JE ERRHERE ;如果为0则打印错误消息 MOV COUNTB,AL ;写入人数 CBW ;字节扩展 MOV COUNTW,AX PRINTTIP CR POP BX ;恢复现场 POP AX RET GETNUMBER ENDP ;-------------------------------------------------------- ;循环直到输入人数满时终止,获得输入的字符串 GETINFO PROC NEAR PUSH AX ;保护现场 PUSH BX PUSH CX PUSH DX