學生成績管理系統(彙編)
程式設計軟體: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