【正确答案】DSEG SEGMENT
COUNT EQU 32
SCORE1 DW 32 DUP(0) ;存放32名学生成绩(BCD码)
SCORE2 DB 32 DUP(0) ;存放32名学生成绩(二进制)
TEMP1 DB 4 DUP(0) ;暂时存放某学生成绩
TEMP2 DB 3 DUP(0)
ZGF1 DB 0 ;最高分(二进制)
ZDF1 DB 0FFH ;最低分(二进制)
PJF1 DB 0 ;平均分(二进制)
ZGF2 DW 0 ;最高分(压缩的BCD码)
ZDF2 DW 0 ;最低分(压缩的BCD码)
PJF2 DW 0 ;平均分(压缩的BCD码)
S90_100DW 0 ;90~100分数段人数
S80_89 DW 0 ;80~89分数段人数
S70_79 DW 0 ;70~79分数段人数
S60_69 DW 0 ;60~69分数段人数
S0_59 DW 0 ;不及格分数段人数
FILE DB 'SCORE.txt',0 ;定义输出文件名字符串
HANDLE DW ? ;保存输出文件句柄
BUF DB 1024DUP(0) ;文件缓冲区
COUNT2 DW ? ;读入缓冲区BUF的字节数
STR1 DB 0DH,0AH,'请输入学生成绩(按回车结束): $'
STR2 DB 0DH,0AH,'学生学号: $' ;输入学号提示
STR3 DB 0DH,0AH,'注意: 输入数据非法(非字符数字或大于100).请重新输入: $,
;输入非法,重新输入提示
STR4 DB 0DH,0AH,'最高分: $' ;最高分提示
STR5 DB 0DH,0AH,'最低分: $' ;最低分提示
STR6 DB 0DH,0AH,'平均分: $' ;平均分提示
STR7 DB 0DH,0AH,'分数在90~100之间的人数: $';分数在90~100之间的人数提示
STR8 DB 0DH,0AH,'分数在80~89之间的人数: $' ;分数在80~89之间的人数提示
STR9 DB 0DH,0AH,'分数在70~79之间的人数: $' ;分数在70~79之间的人数提示
STR10 DB 0DH,0AH,'分数在60~69之问的人数: $' ;分数在60~69之间的人数提示
STR11 DB 0DH,0AH,'分数在0~59之间的人数: $' ;不及格人数提示
DSEG ENDS
SSEG SEGMENT
STACK DB 100DUP(0)
SSEG ENDS
CODE SEGMENT
ASSUME CS: CODE,DS: DATA;SS: SSEG
MAIN PROC FAR
SCTJJG MACRO X,Y ;输出对分数进行的某项统计值宏定义
MOV AX,X ;取对分数进行的某项统计值(压缩的BCD码)
CALL, BCDTASC ;调用将某项统计值(压缩的BCD码)转换为ASCⅡ码子程序
LEA DX,Y ;取某项统计值偏移地址
CALL PMXSSC ;调用输出某项统计值子程序
ENDM
START: MOV AX,DSEG ;段地址装填
MOV DS,AX
MOV AX,SSEG ;堆栈段地址装填
MOV SS,AX
MOV SP,LENGTH STACK
CALL JPSR ;调用键盘输入子程序,输入学生成绩
CALL FSTJ ;调用对分数进行各项统计子程序
CALL PMCSH ;调用屏幕初始化子程序,清屏、光标定位等
SCTJJG ZGF2,STR4 ;宏调用,输出最高分
SCTJJG ZDF2,STR5 ;宏调用,输出最低分
SCTJJG PJF2,STR6 ;宏调用.输出平均分
SCTJJG S90~100,STR7 ;宏调用,输出90~100分数段人数
SCTJJG S80~89,STR8 ;宏调用,输出80~89分数段人数
SCTJJG S70~79,STR9 ;宏调用,输出70~79分数段人数
SCTJJG S60~69,STR10 ;宏调用,输出60~69分数段人数
SCTJJG S0~59,STR11 ;宏调用,输出0~59分数段人数
CALL WJCL ;调用文件处理子程序。将屏幕显示内容送入SCORE.txt
MOV AX,4COOH
INT 21H ;键盘输入学生成绩子程序
JPSR PROC
MOV DX,OFFSET STR1 ;输入学生成绩提示
MOV AH,09H
INT 21H
LEA DI,SCORE1
LEA SI.SCORE2
MOV CX,COUNT
MOV BH,30H ;BH用于处理学号十位数字
MOV BL,31H ;BL用于处理学号个位数字
;外循环处理32个成绩
LOP1: MOV STR2+11,BH ;将学号值嵌入“学生学号: ”提示中
MOV STR2+12,BL
MOV DX,OFFSET STR2;输入学生学号提示
MOV AH,09H
INT 21H
LOP2: PUSH AX ;内循环处理每一个成绩
PUSH BX
PUSH CX
PUSH DX
LOP7: XOR CX,CX
LEA BX,TEMP1 ;TEMP1临时存放分数
LOP3: MOV AH,01
INT 21H
CMP AL,0DH ;按回车键表示一个分数输入结束
JE LOP4
CMP AL,'0'H ;检查输入数据的合理性: '0'~'9,合理
JB LOP6 ;输入字符小于'0',转
CMP AL,'9'
JA LOP6 ;输入字符大于'9',转
SUB AL,30H
MOV [BX],AL
INC CH ;记录输入分数的位置
CMP CH,3
JA LOP6 ;输入分数位数大于3(输入分数大于100),转
INC BX
JMP LOP3
LOP6: MOV DX,OFFSET STR3 ;输入非法,重新输入提示
MOV AH,09H
INT 21H
JMP LOP7;转,重新输入一个分数
LOP4: CALL BCDTBIN ;将TEMP1中的一个分数(非压缩BCD码)转换为二进制数,出
口参数在AL中
MOV [SI],AL ;分数的二进制形式送入SCORE2中
CMP AL,100
JA LOP6 ;输入分数大于100,转
CALL FYSTYSB ;调用非压缩BCD码转换成压缩BCD码的子程序。入口参数在
TEMP1和DI、CH中
POP DX
POP CX
POP BX
POP AX
INC BL ;用于处理学号提示
CMP BL,'9'
JLE LOP8 ;输入字符大于'9',转
AND BL,0F0H
INC BH
LOP8: INC DI
INC DI
INC SI
DEC CX
JNZ LOP1
RET
JPSR ENDP
;对分数进行各项统计子程序
FSTJ PROC
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV SI,OFFSET SCORE1
MOV DI,OFFSET SCORE2
MOV CX,COUNT
XOR AX,AX ;AX用于累加全部分数
FLOP1: MOV DL,ZGF1 ;求最高分
MOV DH,[DI] ;取分数的二进制形式数据送DH
CMP DH,DL
JBE FLOP2
MOV ZGF1,DH ;获得最高分
PUSH AX
MOV AX,[SI]
MOV ZGF2,AX
POP AX
FLOP2: MOV DL,ZDF1 ;求最低分
CMP DH,DL
JAE FLOP3
MOV ZDF1,DH ;获得最低分
PUSH AX
MOV AX,[SI]
MOV ZDF2,AX
POP AX
FLOP3: ADD AL,DH ;累加全部分数
ADC AH,0
CMP DH,90 ;统计90~100分数段的人数
JB FLOP4
INC S90_100
JMP FLOP8
FLOP4: CMP DH,80;统计80~89分数段的人数
JB FLOP5
INC S80_89
JMP FLOP8
FLOP5: CMP DH,70 ;统计70~79分数段的人数
JB FLOP6
INC S70_79
JMP FLOP8
FLOP6: CMP DH,60 ;统计60~69分数段的人数
JB FLOP7
INC S60_69
JMP FLOP8
FLOP7: INC S0_59 ;统计不及格的人数
FLOP8: INC DI
INC SI
INC SI
LOOP FLOP1
MOV BL,COUNT
DIV BL ;累加的全部分数÷32=平均分,送入AL
MOV PJF1,AL
CALL BINTBCD ;将PJF1(二进制数)转换为压缩的BCD码,并送入PJF2。入口
参数在AL中,出口参数在AX中
MOV PJF2,AX
MOV AX,S90_100
CALL BINTBCD ;将S90~100(二进制数)转换为压缩的BCD码,再返还S90~100。入口参数在AL中,出口参数在AX中
MOV S90_100,AX
MOV AX,S80_89
CALL BINTBCD ;将S80~89(二进制数)转换为压缩的BCD码,再返还S80~89。入口参数在AL中,出口参数在AX中
MOV S80_89,AX
MOV AX,S70_79
CALL BINTBCD ;将S70~79(二进制数)转换为压缩的BCD码,再返还S70~79。
入口参数在AL中,出口参数在AX中
MOV S70_79,AX
MOV AX,S60_69
CALL BINTBCD ;将S60~69(二进制数)转换为压缩的BCD码,再返还S60~69。入口参数在AL中,出口参数在AX中
MOV S60_69,AX
MOV AX,S0_59
CALL BINTBCD ;将S0~59(二进制数)转换为压缩的BCD码,再返还S0~59。入口参数在AL中,出口参数在AX中
MOV S0_59,AX
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
RET
FSTJ ENDP
;压缩BCD码转换成为非压缩BCD码的子程序。入口参数在AL中出口参数在AX中
YSBTFYS PROC
PUSH CX
MOV AH,AL
MOV CL,4
SHR AH,CL
AND AL,0FH
POP CX
RET
YSBTFYS ENDP
;压缩BCD码转换成为ASC码的子程序。入口参数在AL中,出口参数在TEMP1中
BCDTASC PROC
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV TEMP1,'' ;将存放百位数字的内存单元预置空格,以避免出现73为073的情况
MOV TEMPI+1,'' ;将存放十位数字的内存单元预置空格
MOV TEMP1+2,'' ;将存放个位数字的内存单元预置空格
CMP AH,0
JZ BCLOP1
ADD AH,30H ;处理百位数
MOV TEMP1,AH
BCLOP1: CALL YSBTFYS
CMP TEMP1,''
JNZ BCLOP2 ;TEMP1不等于空格,转
CMP AH,0
JZ BCLOP3 ;十位数字等于0,且TEMP1等于空格,转
BCLOP2: ADD AH,30H ;处理十位数
MOV TEMP1+1,AH
BCLOP3: ADD AL,30H ;处理个位数
MOV TEMP1+2,AL
MOV TEMP1+3,'$,
POP DI
POP SI
POP DX
POP CX
POP BX
RET
BCDTASC ENDP
;非压缩BCD码转换成为压缩BCD码的子程序。入口参数在TEMP1和DI和CH中
FYSTYSB PROC
PUSH AX
PUSH BX
PUSH DX
PUSH SI
LEA BX,TEMP1 ;一个合法分数TEMP1(非压缩BCD码)转换为压缩
;BCD码后送入SCORE1
MOV AL,CH
XOR AH,AH
ADD BX,AX
DEC BX ;从输入分数的个位开始的压缩BCD码调整
XOR AX,AX
MOV AL,[BX] ;取输入分数的个位数
DEC CH
JZ FIOP ;取完输入分数的数字位,转
DEC BX
MOV AH,[BX] ;取输入分数的十位数
MOV CL,4
ROR AH,CL
OR AL,AH ;合并输入分数的十位数和个位数到AL中
XOR AH,AH
DEC CH
JZ FLOP ;取完输入分数的数字位,转
DEC BX
MOV AH,[BX] ;取输入分数的百位数
FLOP: MOV [DI],AX ;将处理后的分数送SCORE1
POP SI
POP DX
POP BX
POP AX
RET
FYSTYSB ENDP
;屏幕初始化子程序,清屏、光标定位等
PMCSH PROC
W_TOP=0 ;窗口左上角行号
W LEFT=0 窗口左上角列号
W BOTTOM=24 ;窗口右下角行号
W BOTTOM=79 ;窗口右下角列号
W PROPERTY=7 ;属性值,黑底白字
PAGE N0=0 显示页号
MOV AL,PAGE NO
MOV AH,5
INT 10H ;设置当前页,AL=页号
MOV CH,W_TOP
MOV CH,W_LEFT
MOV DH,W_BOTTOM
MOV DL,W_RIGHT
MOV BH,PROPERTY
MOV AL,0
MOV AH,6
INT 10H ;上卷指定窗口
MOV BH,PAGE_NO ;光标定位到窗口左上角
MOV DH,W_TOP
MOV DL,W_LEFT
MOV AH,2
INT 10H
RET
PMCSH ENDP
;屏幕显示输出子程序。入口参数在TEMP1和DX中
PMXSSC PROC
PUSH AX
PUSH DX
MOV AH,09H
INT 21H
LEA DX,TEMP1
INT 21H
POP DX
POP AX
RET
PMXSSC ENDP
;文件处理子程序
WJCL PROC
MOV AH,3CH ;建立文件
MOV CX,20H ;正常文件属性
LEA DX,FILE
INT 21H
MOV HANDLE,AX ;保存输出文件句柄
MOV SI,160 ;本段程序将显示器显示的内容复制到数据缓冲区
;BUF,从显示器的第二行开始
LEA DI,BUF
MOV CH,8 ;共复制显示器8行内容
XOR DX,DX ;读入缓冲区BUF的显示器文件的字节数
WLOP1: PUSH SI
MOV CL,80 ;显示器每行显示80个字符
WLOP2: MOV AX,08800H ;彩显卡段地址
MOV DS,AX
MOV BX,[SI]
MOV AX,SEG BUF ;数据缓冲区段地址
MOV DS,AX
MOV [D1],BL ;将读入显示器字符的ASCⅡ码送入BUF
INC DX
INC DI
INC SI
INC SI
DEC CL
JNZ WLOP2
;以下6行代码用来将刚读入BUF的一行显示器的内容从尾部开始.删除连续空格,直到遇到
一个非空格字符,BUF指针DI同步减少
WLOP4: DEC DI
MOV BL,[DI]
CMP BL,20H
JNZ WLOP3
DEC DX
JMP WLOP4
;以下5行代码用来在从BUF送入的显示器每一行字符最后添加回车、换行符号.以使BUF输出到文本文件的内容能自动换行
WLOP3: INC DI
MOV BYTE PTR[DI],0DH;
INC DI
INC DX
MOV BYTE PTR[DI],0AH
INC DI
INC DX
POP SI
ADD SI,160 ;为扫描显示器下一行内容做准备
DEC CH
JNZ WLOP1
MOV COUNT2,DX
MOV AX,DSEG
MOV DS,AX
LEA DX,BUF ;数据缓冲区偏移地址
MOV CX,COUNT2 ;取出已读入文件字节数
MOV BX,HANDLE ;取输出文件句柄
MOV AH,40H ;顺序写
INT 21H ;关闭输出文件
MOV AH,3EH
MOV BX,HANDLE
INT 21H
RET
WJCL ENDP
;非压缩BCD码转换为二进制数
BCDTBlN PROC
PUSH BX
PUSH CX
PUSH DX
PUSH SI
XOR AL,AL
LEA SI,TEMP1
LOOP1: MOV DL,[SI]
MOV BL,AL ;出口参数由AL带出
SHL AL,1
SHL AL,1
ADD AL,BL
SHL AL,1
ADD AL,DL
DEC CH
JZ LOOP2 ;十进制BCD码数位转换完,转
INC SI
JMP LOOP1
LOOP2: POP SI
POP DX
POP CX
POP BX
RET
BCDTBIN ENDP
;SCORE1(BCD码)转换为SCORE2(二进制)
SCOTSCO2 PROC
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
LEA SI,SCORE1
LEA DI,SCORE2
MOV DX,COUNT
SLOP1: MOV BX,[SI]
MOV AX,BX
SHL AH,1
SHL AH,1
ADD AH,BH
SHL AH,1
MOV CL,4
SHR BL,CL
ADD AH,BL
MOV BH,AH
SHL AH,1
SHL AH,1
ADD AH,BH
SHL AH,1
AND AL,0FH
ADD AH,AL
MOV [DI],AH
INC SI
INC SI
INC DI
DEC DX
JNZ SLOP1
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
RET
SCOTSCO2 ENDP
;二进制数转换为压缩BCD码。入口参数在AL中,出口参数在AX中
BINTBCD PROC
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV TEMP2,0
MOV TEMP2+1.0
MOV TEMP2+2.0
LEA DI,TEMP2
MOV BL,10
BLOP1: CMP AL,0
JZ BLOP2
XOR AH,AH
DIV BL
MOV [DI],AH
INC D1
JMP BLOP1
BLOP2: MOV AH,TEMP2+1 ;取十位数字
MOV CL,4
SHL AH,CL
MOV AL,TEMP2 ;取个位数字
OR AL,AH ;十位和个位数字合并
MOV AH,TEMP2+2 ;取百位数字
POP DI
POP SI
POP DX
POP CX
POP BX
RET
BINTBCD ENDP
MAIN ENDP
CSEG ENDS
END START
【答案解析】本练习是对一个班级的学生进行成绩统计管理分析,是综合性比较强的题目。目的是通过该题目规范学生的编程思路。该题目比较完整,不仅有键盘输入,还有数据合理性验证,将录入数据经格式化处理后存放在要求的位置,同时还包含文件管理和屏幕输出显示部分。