1. 程式人生 > >學生成績管理系統(彙編)

學生成績管理系統(彙編)

程式設計軟體:Masm for Windows 整合實驗環境 2015

巨集和子程式部分已經被提取出來,原先程式已經詳細註釋了,只是稍作美化了一下,為了方便理解,建議讀者先理解一下結構體,如何用地址的方法,準確定位到資料,雖然使用的是結構體儲存資料,但是存取改資料,我個人還是使用的地址定位的方法,所以結構體後面的地址,是相對地址,只要理解地址如何取用資料,就會方便理解程式碼了;另外,本人編寫過程中,傳遞的引數使用的極少,所以子程式呼叫的時候,可能有些暫存器內的資料已經在上一段程式中被定義好了,如果要理解程式,閱讀起來可能有點亂,所以暫存器裡面的資料如果能記住,讀程式碼就會方便很多,主要需要記得是BX,DX,CX,SI,DI(BP只在查詢學號並修改成績中有用到) ,BX我主要是用來存結構體的首位地址,還有結構體中資料每一行的首地址,ADD BX,TYPE  students 就是換行的方式,DX主要儲存一些資料,CX則是計數器,SI有時候也作為計數器,SI和DI也會當做相對定位的指標,準確定位到每一個位元組區域,用來配合BX的找出結構體中的資料,結構體資料儲存方式如下

BX(結構體首地址) DI(0) DI(1) DI(2) DI(3) DI(4) DI(5) DI(6) DI(7) DI(8) DI(9) DI(10) DI(11) DI(12) DI(13) ... ... ...
BX+TYPE students DI(0) ... ... ... ... ...                      
.....                                  
.....                                  
.....                                  

 

上面每一個小格就是一個位元組單元,SNO:DI(0~8)為學號儲存單元可存9個位元組資料,NAME:DI(9~12)為名字儲存單元可存4個位元組資料,GRADE:DI(13)為成績單元存入0~100的成績,所以只需要一個位元組單元。SORT:剩餘的是多出來的部分,防止資料錯位,以字型對齊。理解上述部分,資料儲存方式,程式就通俗易懂了,彙編主要還是理解程式碼在機器內的運作方式,只要懂得機器內如何運作程式碼,彙編就容易上手了。。。改變程式碼內的N值,可控制輸入學生資訊的個數,以下N=5。按空格結束,所有結束方式均為按空格。。。

執行結果如下圖:

資料輸入:

資料排序輸出:

按學號查詢並修改成績:

 

退出程式:

1.巨集定義部分

  • ;字元輸出巨集定義

SHUCHU MACRO X

    MOV AH,2

    MOV DL,X

    INT 21H

ENDM

  • ;字串輸出巨集定義

S_SHUCHU MACRO Y
    LEA DX,Y
    MOV AH,9
    INT 21H
ENDM

  • ;單字元輸入巨集定義

SHURU MACRO
    MOV AH,1
    INT 21H
ENDM

  • ;字元檢測

CHECK MACRO X
    .IF X>'9' || X<'0' && X!=' '
        S_SHUCHU HINT3            ;提示輸入錯誤
        SHURU                    ;讓提示顯示,避免被刷掉,按任意鍵返回主選單
        JMP RESTORE                ;跳回主選單
    .ENDIF

ENDM

  • ;成績輸出巨集定義

GR_SHUCHU MACRO X
    MOV AL,X        ;接收成績
    MOV AH,0        ;AX高位清0
    MOV CL,10        ;除數,等會用來取餘數和商
    MOV DH,0        ;壓棧前高位置0
    .WHILE AL != 0  ;如果商不為0,則繼續除10
        DIV CL
        MOV DL,AH    ;餘數置於DL
        ADD DL,30H  ;轉換為ASCII碼
        PUSH DX        ;壓棧
        INC DH
    MOV AH,0        ;高位即餘數清0
    .ENDW
    ;迴圈完成取數操作,即從右到左,從個位數開始取數,一直到最高位停止取數
    .IF DH == 0                ;判斷輸入成績是否為0,若為0直接輸出
        SHUCHU 30H
    .ELSE                    ;否則彈出棧中相應內容輸出
            MOV CL,DH
        .WHILE CL
            POP DX
            SHUCHU DL
            DEC CL
        .ENDW
    .ENDIF            ;成績輸出結束
ENDM

 2.子程式定義部分

  • ;成績輸入子程式

GR_SHURU PROC
     MOV CX,0
     MOV DL,10
    .WHILE CX<=100
        SHURU            ;鍵盤接收一個字元
        CHECK AL            ;檢測輸入的是否為數字
    .IF AL == ' '
        MOV [BX+DI],CL        ;如果輸入空格,則成績接收結束,並存入對應儲存單元,即結構體GRADE單元
        RET
    .ELSE
        SUB AL,30H        ;進行ASCII碼轉換為數字
        CBW                ;AL擴充套件為AX,高位清0
        XCHG CX,AX        ;交換數值
        MUL DL            ;AL×10放入AX中
        ADD CX,AX        ;將數字相加,得到新的數值,放入cl中
    .ENDIF
    .ENDW
    S_SHUCHU WARING        ;成績輸入不合格輸出警告
    RET
GR_SHURU ENDP
    

  • ;選單顯示子程式

SHOW PROC NEAR
    MOV AX,3  ;清屏
    INT 10H
    S_SHUCHU LIST
    RET
SHOW ENDP

;選單選項子程式
CHOICE PROC NEAR
    SHURU        ;呼叫巨集輸入一個字元
    .IF AL=='1'         ;呼叫輸入功能
        CALL INPUT
    .ELSEIF AL =='2'    ;呼叫輸出功能,且排序
        CALL RANK        ;呼叫排序,對資料按成績進行排序,由高到低
        CALL OUTPUT
    .ELSEIF AL=='3'        ;呼叫查詢功能
        CALL SEARCH
    .ELSEIF AL=='0'        ;退出程式    
        JMP EXIT
    .ELSE
        S_SHUCHU WARING        ;輸出警告提示
    .ENDIF
    SHURU    ;接收一個字元,用於暫停當前介面,按任意鍵重新整理選單
    RET
CHOICE ENDP

  • ;輸入子程式

INPUT PROC NEAR
    S_SHUCHU HINT1
    
    LEA BX,STU_ARRAY        ;結構體初始化指標,行定位
    MOV SI,0                ;統計輸入的行數
    
    .WHILE SI<N                ;N為行數,控制輸入幾行
      
 MOV CX,9            ;迴圈,學號共定義9個位元組空間
        MOV DI,0            ;相對指標,用於定位對應的結構體內的元素,列定位
    LPI:
        SHURU
        CHECK AL        ;檢測輸入字元是否為數字
        .IF AL == ' '
            JMP XHI            ;若輸入空格,則跳到下一項輸入
        .ELSE
            MOV [BX+DI],AL     ;將學號逐個輸入到對應的位置,最大9位
            INC DI
        .ENDIF
        LOOP LPI
    XHI:
        SHUCHU '    '
        MOV CX,4        ;姓名輸入,最大可輸入4個字元
        MOV DI,9        ;結構體定義的NAME段位置定位
    LPI1:
        SHURU
        .IF AL == ' '    
            JMP XMI        ;輸入空格表示輸入下一項
        .ELSE
            MOV [BX+DI],AL  ;對應位置存入相應字元,最多輸入4位
            INC DI
        .ENDIF
        LOOP LPI1
    XMI:
        SHUCHU '    '
        MOV DI,13        ;定位到GRADE區域,成績輸入
        CALL GR_SHURU        ;呼叫子程式,成績輸入
        
        ADD BX,TYPE students    ;跳到下一行,即結構體數字的下一行,加上相應的結構體大小
        INC SI                ;行數統計自增一次
        SHUCHU 13
        SHUCHU 10
    .ENDW    
    RET
INPUT ENDP

 

  • ;輸出子程式

OUTPUT PROC NEAR    ;該部分可參照輸入子程式,理解地址所對應資料,方便理解程式碼
    S_SHUCHU HINT2
    
    LEA BX,STU_ARRAY
    MOV SI,0
    
    .WHILE SI<N
        MOV CX,9
        MOV DI,0
    LPO:
        MOV DL,[BX+DI]
        SHUCHU DL
        INC DI
        LOOP LPO
        
        SHUCHU '    '
        MOV CX,4
    LPO1:
        MOV DL,[BX+DI]
        SHUCHU DL
        INC DI
        LOOP LPO1
        
        SHUCHU '    '
        MOV DL,[BX+DI]
        GR_SHUCHU DL
        
        ADD BX,TYPE students
        INC SI
        
        SHUCHU '    '
        MOV DX,SI        ;獲取當前的行數
        GR_SHUCHU DL    ;將行數轉換為對應的ASCII碼,輸出對應的行數
        
        SHUCHU 13
        SHUCHU 10
    .ENDW
    RET    
OUTPUT ENDP

  • ;降序排序

RANK PROC NEAR
    MOV CX,N-1            ;總的資料個數減一,即迴圈次數
.WHILE CX                ;氣泡排序法
    PUSH CX                ;外迴圈次數保護,壓棧
    LEA BX,STU_ARRAY    ;回到結構體的第一行
    .WHILE CX
        MOV DI,13
        MOV DL,[BX+DI]        ;取到的第一個值,與它的後一位值比較,對應到結構體為GRADE部分
        MOV DH,[BX+DI+14]    ;取到的第二個值,與其前一位比較,同上
            .IF DL<DH        ;如果前一個小於後一個成績,則進行資料交換
            MOV DI,0
                .WHILE DI<14                ;結構體實際長度為14
                    XCHG AL,[BX+DI]
                    XCHG [BX+DI+14],AL        ;.while內為前後資料交換部分
                    XCHG [BX+DI],AL
                    INC DI
                .ENDW
            .ENDIF
        ADD BX,TYPE students    ;跳到第二個位置與後一段資料比較,氣泡排序法
        DEC CX                    ;內迴圈自減
    .ENDW
    POP CX
    DEC CX                        ;外迴圈自減
.ENDW
    RET
RANK ENDP

  • ;查詢並修改子程式

SEARCH PROC NEAR
    S_SHUCHU FIND
    
    LEA BX,STU_ARRAY    ;取儲存資料的首地址,即結構體首地址
    LEA BP,SOURCE        ;存放查詢的學號的首地址
    
    MOV CX,9            ;迴圈,學號共定義了9個位元組空間
    MOV DI,0            ;相對指標,用於定位需要存入元素,列定位
LPF:
    SHURU
    CHECK AL        ;檢測輸入字元是否為數字
    .IF AL == ' '
        JMP FNXT            ;若輸入空格,則跳到下一項輸入
    .ELSE
        MOV [BP+DI],AL     ;將學號逐個輸入到對應的位置,最大9位
        INC DI
    .ENDIF
    LOOP LPF
FNXT:
    MOV CX,N        ;查詢對比的個數,即總共的行數(學生數)
LPF1:
    PUSH CX            ;保護外迴圈次數,壓棧
        MOV CX,9    ;學號一共有9個儲存區域
        MOV DI,0
    LPF2:                    
        MOV AL,[BX+DI]        ;結構體,已經存入的資料
        MOV AH,[BP+DI]        ;查詢輸入的學號
        CMP AL,AH            ;按位對比學號
        JNZ FNXT1            ;如果有一個沒有相等則跳過該學生,該學生不是要查詢的學生
        INC DI
        .IF DI == 9
            POP CX            ;彈出多餘的CX,避免無法返回,即RET執行和棧有關,需先彈出棧中多餘的資料,避免程式執行出錯
            JMP FNXT2        ;如果查詢到對應學號則跳出,執行修改成績程式段
        .ENDIF
    LOOP LPF2                ;迴圈9次對比完一位的學號
        FNXT1:
        ADD BX,TYPE students    ;指向下一個學生,即下一行資料區域
        POP CX                ;外迴圈被保護的CX,出棧
LOOP LPF1                    ;一共對比N次,即和N個學生的學號比較
    S_SHUCHU NFIND    
    RET
FNXT2:
    S_SHUCHU HINT4
    MOV SI,13                ;指標指向GRADE對應段
    MOV DL,[BX+SI]            ;get到原始成績
    GR_SHUCHU DL            ;輸出舊的成績
    S_SHUCHU HINT5            ;提示是否修改成績
    SHURU                    ;接收字元,判斷是否修改成績
    .IF AL=='y'
        S_SHUCHU RESULT
        MOV DI,13
        CALL GR_SHURU            ;呼叫輸入成績子程式
    .ENDIF
    RET
SEARCH ENDP

原始碼如下:

students STRUCT			 ;偏移量
	SNO DB 9 DUP(?)  	 ;0-8
	NAME DB 4 DUP(?)	 ;9-12
	GRADE DB ?			 ;13
	SORT DD ?   		 ;14
students ENDS   ;結構體共16個位元組

DATAS SEGMENT
	N = 4			;陣列大小定義
    STU_ARRAY students N DUP(<>)  ;結構體陣列
    JIANGE DD 10 DUP (?)  ;資料溢位顯示遮擋選單
    LIST DB 13,10
    	DB '*~*~*~*~*~*~*~LIST*~*~*~*~*~*~*~*~*~*~*',13,10
    	DB '@         1.INPUT                     @',13,10
    	DB '@         2.OUTPUT(RANK)              @',13,10
    	DB '@         3.FIND(SNO)                 @',13,10
    	DB '@         0.QUIT                      @',13,10
    	DB '*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*',13,10
    	DB 'PLEASE INPUT YOUR CHOICE:$'
    WARING DB 'INPUT ERROR!!!$'
    HINT1 DB 13,10,'SNO		NAME	GRADE',13,10,'$'
    HINT2 DB 13,10,'SNO		NAME	GRADE	RANK',13,10,'$'
    HINT3 DB 13,10,'INPUT ERROR! PLEASE AFRESH.',13,10,'$'
    HINT4 DB ' OLD GRADE:$'
    HINT5 DB 13,10,'ARE THE SCORES MODIFIED?(y/n)',13,10,'$'
    FIND DB 13,10,'PLEASE ENTER THE (SNO) YOU WANT TO FIND,END BY SPACE:',13,10,'$'
    NFIND DB 13,10,'NOT FOUND!!',13,10,'$'
    RESULT DB 13,10,'PLEASE ENTER NEW GRADE:',13,10,'$'
    SOURCE DB 9 DUP(?)
DATAS ENDS

;字元輸出巨集定義
SHUCHU MACRO X
	MOV AH,2
	MOV DL,X
	INT 21H
ENDM

;字串輸出巨集定義
S_SHUCHU MACRO Y
	LEA DX,Y
	MOV AH,9
	INT 21H
ENDM

;單字元輸入巨集定義
SHURU MACRO
	MOV AH,1
	INT 21H
ENDM

;字元檢測
CHECK MACRO X
	.IF X>'9' || X<'0' && X!=' '
		S_SHUCHU HINT3			;提示輸入錯誤
		SHURU					;讓提示顯示,避免被刷掉,按任意鍵返回主選單
		JMP RESTORE				;跳回主選單
	.ENDIF

ENDM

;成績輸出巨集定義
GR_SHUCHU MACRO X
	MOV AL,X        ;接收成績
	MOV AH,0		;AX高位清0
	MOV CL,10		;除數,等會用來取餘數和商
	MOV DH,0		;壓棧前高位置0
	.WHILE AL != 0  ;如果商不為0,則繼續除10
		DIV CL
		MOV DL,AH	;餘數置於DL
		ADD DL,30H  ;轉換為ASCII碼
		PUSH DX		;壓棧
		INC DH
	MOV AH,0		;高位即餘數清0
	.ENDW
	;迴圈完成取數操作,即從右到左,從個位數開始取數,一直到最高位停止取數
	.IF DH == 0				;判斷輸入成績是否為0,若為0直接輸出
		SHUCHU 30H
	.ELSE					;否則彈出棧中相應內容輸出
			MOV CL,DH
		.WHILE CL
			POP DX
			SHUCHU DL
			DEC CL
		.ENDW
	.ENDIF			;成績輸出結束
ENDM

	;主程式程式碼段         MAIN
CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS
START:
    MOV AX,DATAS
    MOV DS,AX
    
RESTORE:			;輸入錯誤後,跳回的點
	.WHILE 1
	CALL SHOW   ;呼叫選單
	CALL CHOICE ;接收選項並呼叫對應子程式
	.ENDW		;死迴圈

EXIT:    
	MOV AH,4CH
    INT 21H
	;主程式程式碼段結尾		MAIN	

;成績輸入子程式
GR_SHURU PROC
 	MOV CX,0
 	MOV DL,10
	.WHILE CX<=100
		SHURU			;鍵盤接收一個字元
		CHECK AL			;檢測輸入的是否為數字
	.IF AL == ' '
		MOV [BX+DI],CL		;如果輸入空格,則成績接收結束,並存入對應儲存單元,即結構體GRADE單元
		RET
	.ELSE
		SUB AL,30H		;進行ASCII碼轉換為數字
		CBW				;AL擴充套件為AX,高位清0
		XCHG CX,AX		;交換數值
		MUL DL			;AL×10放入AX中
		ADD CX,AX		;將數字相加,得到新的數值,放入cl中
	.ENDIF
	.ENDW
	S_SHUCHU WARING		;成績輸入不合格輸出警告
	RET
GR_SHURU ENDP
    
;選單顯示子程式
SHOW PROC NEAR
	MOV AX,3  ;清屏
    INT 10H
    S_SHUCHU LIST
    RET
SHOW ENDP

;選單選項子程式
CHOICE PROC NEAR
	SHURU		;呼叫巨集輸入一個字元
	.IF AL=='1'		 ;呼叫輸入功能
		CALL INPUT
	.ELSEIF AL =='2'	;呼叫輸出功能,且排序
		CALL RANK		;呼叫排序,對資料按成績進行排序,由高到低
		CALL OUTPUT
	.ELSEIF AL=='3'		;呼叫查詢功能
		CALL SEARCH
	.ELSEIF AL=='0'		;退出程式	
		JMP EXIT
	.ELSE
		S_SHUCHU WARING		;輸出警告提示
	.ENDIF
	SHURU	;接收一個字元,用於暫停當前介面,按任意鍵重新整理選單
	RET
CHOICE ENDP

;輸入子程式
INPUT PROC NEAR
	S_SHUCHU HINT1
	
	LEA BX,STU_ARRAY		;結構體初始化指標,行定位
	MOV SI,0				;統計輸入的行數
	
	.WHILE SI<N				;N為行數,控制輸入幾行
		MOV CX,9			;迴圈,學號共定義9個位元組空間
		MOV DI,0			;相對指標,用於定位對應的結構體內的元素,列定位
	LPI:
		SHURU
		CHECK AL		;檢測輸入字元是否為數字
		.IF AL == ' '
			JMP XHI			;若輸入空格,則跳到下一項輸入
		.ELSE
			MOV [BX+DI],AL 	;將學號逐個輸入到對應的位置,最大9位
			INC DI
		.ENDIF
		LOOP LPI
	XHI:
		SHUCHU '	'
		MOV CX,4		;姓名輸入,最大可輸入4個字元
		MOV DI,9		;結構體定義的NAME段位置定位
	LPI1:
		SHURU
		.IF AL == ' '	
			JMP XMI		;輸入空格表示輸入下一項
		.ELSE
			MOV [BX+DI],AL  ;對應位置存入相應字元,最多輸入4位
			INC DI
		.ENDIF
		LOOP LPI1
	XMI:
		SHUCHU '	'
		MOV DI,13		;定位到GRADE區域,成績輸入
		CALL GR_SHURU		;呼叫子程式,成績輸入
		
		ADD BX,TYPE students	;跳到下一行,即結構體數字的下一行,加上相應的結構體大小
		INC SI				;行數統計自增一次
		SHUCHU 13
		SHUCHU 10
	.ENDW	
	RET
INPUT ENDP


;輸出子程式
OUTPUT PROC NEAR	;該部分可參照輸入子程式,理解地址所對應資料,方便理解程式碼
	S_SHUCHU HINT2
	
	LEA BX,STU_ARRAY
	MOV SI,0
	
	.WHILE SI<N
		MOV CX,9
		MOV DI,0
	LPO:
		MOV DL,[BX+DI]
		SHUCHU DL
		INC DI
		LOOP LPO
		
		SHUCHU '	'
		MOV CX,4
	LPO1:
		MOV DL,[BX+DI]
		SHUCHU DL
		INC DI
		LOOP LPO1
		
		SHUCHU '	'
		MOV DL,[BX+DI]
		GR_SHUCHU DL
		
		ADD BX,TYPE students
		INC SI
		
		SHUCHU '	'
		MOV DX,SI		;獲取當前的行數
		GR_SHUCHU DL	;將行數轉換為對應的ASCII碼,輸出對應的行數
		
		SHUCHU 13
		SHUCHU 10
	.ENDW
	RET	
OUTPUT ENDP

;降序排序
RANK PROC NEAR
	MOV CX,N-1			;總的資料個數減一,即迴圈次數
.WHILE CX				;氣泡排序法
	PUSH CX				;外迴圈次數保護,壓棧
	LEA BX,STU_ARRAY	;回到結構體的第一行
	.WHILE CX
		MOV DI,13
		MOV DL,[BX+DI]		;取到的第一個值,與它的後一位值比較,對應到結構體為GRADE部分
		MOV DH,[BX+DI+14]	;取到的第二個值,與其前一位比較,同上
			.IF DL<DH		;如果前一個小於後一個成績,則進行資料交換
			MOV DI,0
				.WHILE DI<14				;結構體實際長度為14
					XCHG AL,[BX+DI]
					XCHG [BX+DI+14],AL		;.while內為前後資料交換部分
					XCHG [BX+DI],AL
					INC DI
				.ENDW
			.ENDIF
		ADD BX,TYPE students	;跳到第二個位置與後一段資料比較,氣泡排序法
		DEC CX					;內迴圈自減
	.ENDW
	POP CX
	DEC CX						;外迴圈自減
.ENDW
	RET
RANK ENDP

;查詢並修改子程式
SEARCH PROC NEAR
	S_SHUCHU FIND
	
	LEA BX,STU_ARRAY	;取儲存資料的首地址,即結構體首地址
	LEA BP,SOURCE		;存放查詢的學號的首地址
	
	MOV CX,9			;迴圈,學號共定義了9個位元組空間
	MOV DI,0			;相對指標,用於定位需要存入元素,列定位
LPF:
	SHURU
	CHECK AL		;檢測輸入字元是否為數字
	.IF AL == ' '
		JMP FNXT			;若輸入空格,則跳到下一項輸入
	.ELSE
		MOV [BP+DI],AL 	;將學號逐個輸入到對應的位置,最大9位
		INC DI
	.ENDIF
	LOOP LPF
FNXT:
	MOV CX,N		;查詢對比的個數,即總共的行數(學生數)
LPF1:
	PUSH CX			;保護外迴圈次數,壓棧
		MOV CX,9	;學號一共有9個儲存區域
		MOV DI,0
	LPF2:					
		MOV AL,[BX+DI]		;結構體,已經存入的資料
		MOV AH,[BP+DI]		;查詢輸入的學號
		CMP AL,AH			;按位對比學號
		JNZ FNXT1			;如果有一個沒有相等則跳過該學生,該學生不是要查詢的學生
		INC DI
		.IF DI == 9
			POP CX			;彈出多餘的CX,避免無法返回,即RET執行和棧有關,需先彈出棧中多餘的資料,避免程式執行出錯
			JMP FNXT2		;如果查詢到對應學號則跳出,執行修改成績程式段
		.ENDIF
	LOOP LPF2				;迴圈9次對比完一位的學號
		FNXT1:
		ADD BX,TYPE students	;指向下一個學生,即下一行資料區域
		POP CX				;外迴圈被保護的CX,出棧
LOOP LPF1					;一共對比N次,即和N個學生的學號比較
	S_SHUCHU NFIND	
	RET
FNXT2:
	S_SHUCHU HINT4
	MOV SI,13				;指標指向GRADE對應段
	MOV DL,[BX+SI]			;get到原始成績
	GR_SHUCHU DL			;輸出舊的成績
	S_SHUCHU HINT5			;提示是否修改成績
	SHURU					;接收字元,判斷是否修改成績
	.IF AL=='y'
		S_SHUCHU RESULT
		MOV DI,13
		CALL GR_SHURU			;呼叫輸入成績子程式
	.ENDIF
	RET
SEARCH ENDP
;結束

CODES ENDS
    END START