微原软件实验:统计成绩并排名

北邮微原软件实验四:子程序设计

一.实验目的:
1.进一步掌握子程序设计方法;
2.进一步掌握基本的 DOS 功能调用.
二.实验内容:
1.从键盘上输入某班学生的某科目成绩.输入按学生的学号由小到大的顺序输入.
2.统计检查每个学生的名次.
3.将统计结果在屏幕上显示.
4.为便于观察,输入学生数目不宜太多,以不超过一屏为宜.输出应便于阅读.尽可能考虑美观.
5.输入要有检错手段.

仙剑95进度汇报

与坏叔叔交手
与坏叔叔交手

没见过这么强大的对手~幸好存档了。打了两回才干掉他们。

编程思路

之前两个实验已经把各个模块做好了。现在只需要把前面的模块拼凑起来,加上排名功能即可。
排名:这里用的方法是把每个学生的成绩跟其他学生比较,算法复杂度极高。考虑到实验要求的人数不多,可采取此方法来减少代码量。

源代码

;----------------------------------
;Exercise 3. 
;input scores in order.
;
;
;1. Ask for user input.(With checking)
;2. Check end_flag.
;3. Not end: append data.
;4. End input: Calculate ranking.
;5. Output


assume cs:codesg,ds:datasg,ss:stacksg

Stacksg SEGMENT STACK 'STACK'
	DB 100H DUP(0)
Stacksg ENDS

datasg segment
	n_student db 00h
	ranking db 100H DUP(1)
	scores db 200H DUP(0) ; the score of each student is represent as 9,9 for 99.
	current_num db 0,0
	end_flag db 0
	illegal_num_msg db 'ooooops,something wrong with your input. $'
	title_string db 'ID',9,'SCORE',9,'RANKING','$'
datasg ends


codesg segment

main proc

initialize:
	sub ax,ax
	mov ax,datasg
	mov ds,ax

get_input:
	call get_2digits_input
	cmp end_flag,1
	jz end_input
	mov bl,n_student
	rol bl,1
	mov bh,00H
	mov al,current_num[0]
	mov scores[bx],al
	mov al,current_num[1]
	mov scores[bx+1],al
	inc n_student
	jmp get_input
	
end_input:
	sub cx,cx
	sub dx,dx
	mov si,0
	mov di,0
	mov cl,n_student
	mov ch,0
loop1:
	push cx
	sub bx,bx ; bx = the n of student that going to compare.
	mov dh,scores[si]  ; Score[0] of current student.
	mov dl,scores[si+1] ; Score[1] of current student.
	mov cl,n_student
	mov ch,0
loop2:
compare10:
	cmp dh,scores[bx]
	jb inc_rank
	cmp dh,scores[bx]
	jz compare1
	jmp next_cmp_student
compare1:
	cmp dl,scores[bx+1]
	jb inc_rank
	jmp next_cmp_student
inc_rank:
	inc ranking[di]
next_cmp_student:
	inc bx
	inc bx
	loop loop2
	
	inc si
	inc si
	inc di
	pop cx
	loop loop1
	
output:
	call print_nl
	lea dx,title_string
	call print_string
	call print_nl
	mov cl,n_student
	mov ch,0
	mov si,0 ; keep track of student id.
	mov bx,0 ; keep track of score position.
out_loop:
	mov ax,si
	call print_num
	mov al,9
	call print_char
	mov al,9
	call print_char
	mov al,9
	call print_char
	mov al,9
	call print_char
	
	mov al,scores[bx]
	call print_num
	mov al,scores[bx+1]
	call print_num
	mov al,9
	call print_char
	mov al,9
	call print_char
	mov al,9
	call print_char
	mov al,9
	call print_char
	
	mov al,ranking[si]
	call print_num

	call print_nl
	inc si
	inc bx
	inc bx
	loop out_loop
	
exit:
	mov ax,4c00H
	int 21H
	
main endp



;--------------------------------------------
; Process: get_2digits_input
; This process would get a 2-digit-decimal number input from DOS.
; This process requires 2 global variables:  end_flag, current_num[2].
; Input: null
; Output: a number(range 0-99 decimal) in current_num[2](global variable). If encounter a end_symbol, set end_flag to 1.

; 1. Initialize variables, set end_flag and current_num to 0.
; 2. Push registers into stack. 
; 3. Get a char input. (input10)
; 4. Check if it is separate_symbol or end_symbol. If it is, end this process. (check_s,check_e)
; 5. Check if the input is legal(range '0' to '9'),and transform to number from ASCII. (check_legal)
; 6. Get another char input.(input1)
; 7. Check if it is separate_symbol or end_symbol. If it is, end this process. ,and check if the input is legal.(range '0' to '9')
; 8. If input legal,add to current_num directly. (add one)
; 9. Pop registers,return. (return)

end_symbol EQU 'e'
separate_symbol EQU ' '

get_2digits_input proc 
	mov end_flag,0
	mov current_num[0],0
	mov current_num[1],0
	push ax
	push bx
	push cx
	push dx

input10:	
	mov ah,01
	int 21h
check_s:
	cmp al,separate_symbol
	jnz check_e
	jmp return
check_e:
	cmp al,end_symbol
	jnz check_legal
	mov end_flag,1
	jmp return
check_legal:
	call check_num
add_tens:
	mov current_num[0],al
	
	
input1:
	mov ah,01
	int 21h
check_s1:
	cmp al,separate_symbol
	jnz check_e1
	jmp return
check_e1:
	cmp al,end_symbol
	jnz check_legal1
	mov end_flag,1
	jmp return
check_legal1:
	call check_num
add_ones:
	mov current_num[1],al
	jmp input10
	
return:
	pop dx
	pop cx
	pop bx
	pop ax
	;-----Debug------
	;call print_nl
	;mov al,current_num[0]
	;call print_num
	;mov al,current_num[1]
	;call print_num
	;----------------
	ret
	
get_2digits_input endp


;--------------------------------------------
; Process: check_num
; This is a sub-process of get_2digits_input
; input: al (ASCII)
; output: al (unsigned integer)

check_num proc
	cmp al,'0'-1H
	jna illegal_num
	cmp al,'9'+1H
	jnb illegal_num
	sub al,'0'-0H
	ret
illegal_num:
	push dx
	call print_nl
	lea dx,illegal_num_msg
	call print_string
	call print_nl
	mov al,0
	pop dx
	ret
check_num endp

;---------------------------
;Process: print_num
;input: al = number
;output: a number char on screen.

print_num proc 
	push dx
	add al,'0'-0h
	mov ah,02h
	mov dl,al
	int 21h
	pop dx
	ret
print_num endp

;---------------------------
;Process:  print_string
;input: DS:DX, set DS:DX to string address,and call this process. The string should end with '$'
;output: Screen.

print_string proc 
	mov ah,09h
	int 21h
	ret
print_string endp

;---------------------------
;Process: Print_nl
;input: Null.
;output: a newline on screen

print_nl proc 
	push dx
	mov ah,02h
	mov dl,0dh
	int 21h
	mov dl,0ah
	int 21h
	pop dx
	ret
print_nl endp

;---------------------
; Process: print_char
;input: DL,the ASCII of the char.
;output: a char on screen

print_char proc 
	mov ah,02h
	int 21h
	ret
print_char endp



codesg ends
end main

问题分析

程序有一个严重的bug,这个bug出现在“数字显示”模块。当人数超过9个人的时候,排名显示出来的数字就会变成字母。因为这个数字显示模块只支持一位数字。