實驗4:(電話本)
要求:
可放50項的電話號碼錶,每項中有姓名(20)和電話號碼(8),存放聯繫人,並且進行排序。並完成添加電話,根據姓名查詢電話,顯示輸出等功能
算法設計:
①數據結構:可放50項的電話號碼錶,每項中有姓名(20)和電話號碼(8)。數據定義則用tel_tab db 50 dup(20 dup(' '),8 dup(' ')),即可滿足,每項用空白符初始化
②.1存放輸入的數據:tel_name和tel_num分別存放用戶輸入的姓名和電話號碼。di初始化爲電話簿tel_tab的首地址,使用movsb完成字符串的賦值,因此,di指向傳送的目標地址,si爲源地址,cx賦值爲傳送的字節數,轉送名字時,cx=20,傳送電話時,cx=8。循環輸入電話簿項中di會跟着movsb而變化,代表接下來用戶傳送的目標位置,而si每次需重置爲緩存區的首地址。這樣就完成了用戶輸入的名字電話存到tel_tab中。在此基礎上,完成排序等功能。
②.2.用戶輸入緩衝區中的數據需要將剩下的空間用空格代替,具體原因會在討論與結論中說明。主要原因是,用戶輸入的字符串一般爲回車符結尾,倘若連回車符也一起賦到了tel_tab中,則在輸出tel_tab中會完成了輸出電話簿信息的效果。所以每次輸入姓名和電話時,要把緩存區剩餘空間(包括回車符)一起用空白符填滿,空白符填入的個數=總長度-輸入字符的長度
③、排序:每次名字轉入電話簿後都要對電話簿進行重新排序(字典序)。採用排序的最佳方法是插入排序,因爲每次插入數據時,tel_tab中的數據都已經排好了,只要找到比用戶輸入名字大的電話簿項時,將次內存後的所有數據都向後移28個字節,然後再把名字和電話存入該位置。
④、輸出:起始地址tel_tab,每輸出28個字符換行回車。
程序實現:(代碼見附錄)
①、輸入名字和電話,剩餘用空白符代替:調用inputname和inputtel子程序即可。
②、將tel_name和tel_num存入tel_tab中,調用stor_name和stor_mun,子程序。主要採用movsb命令符
③、指定字符串後移28個字節: moveto28byte子程序,因爲電話簿每一項長度爲28個字節,所以cx賦值28,然後si字符串首地址,di=si+28,使用movsb傳送
④、插入排序:需要一個變量tel_count來存放電話簿項個數,當插入數據時比較到比自己大時,從電話簿最後一項開始,每一項調用moveto28byte子程序,然後再將數據放到電話簿中
⑤、輸出電話簿:cx=28*tel_count。
⑥、查詢名字並輸出:用sea_name緩衝區存放要查詢的名字(記得用空白符將剩下空間填滿)。匹配兩字符串是否相等,教課書上有代碼就不再多說,把名字都遍歷一遍,如果匹配成功,另匹配到的名字首地址加上20個字節,即爲對應的電話號碼首地址,將其輸出即可。
DATAS SEGMENT
;此處輸入數據段代碼
tel_name db 20
namelen db 0
namefld db 20 dup(?)
tel_num db 8
numlen db 0
numfld db 8 dup(?)
tel_tab db 50 dup(20 dup(' '),8 dup(' '))
tel_count db 0
pushunit db 0
turnnewline db 28
string1 db 'Input name:$'
string2 db 'Input a telephone number:$'
string3 db 'Please add telephone into table(n/y)$'
string4 db 'search telephone by name:$ '
string5 db 'noresult$'
strSeaName db 20 ;根據名字查詢電話
seanamelen db 0
seanamefld db 20 dup(?)
outputname db 0 ;查詢電話時記錄匹配不成功的次數
DATAS ENDS
STACKS SEGMENT
;此處輸入堆棧段代碼
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov es,ax
cld
lea di,tel_tab
; 輸出Inputname
addphone:
mov dx,offset string3
call print
mov ah,01h
int 21h
call printnewline
;cmp al,59h
;jne searchphone
cmp al,79h
jne printtable ;如果鍵入不是y或Y則進入查詢號碼
mov dx,offset string1
call print
call Inputname
call stor_name ;把名字存放在tel_tab中
mov dx,offset string2
call print
call inputtel
call stor_num ;把電話存放在tel_tab中
call name_sort ;排序
jmp addphone
printtable: ;打印電話簿
lea bx,tel_tab
;lea dx,tel_tab
;call moveto28byte
mov al,tel_count
mov ah,28
mul ah
mov cx,ax
printtableline:
mov dl,[bx]
mov ah,02h
int 21h
inc bx
dec turnnewline
mov al,turnnewline
cmp al,0
jne nochange1
mov turnnewline,28
call printnewline
nochange1: loop printtableline
namesearch: ;查詢電話
mov dx,offset string4
call print
lea dx,strSeaName
call cin
call printnewline
mov bl, seanamelen
mov cx, 20
sub cx, bx
namebrk1: ;將人名除外所剩下的字符用空格填滿
mov seanamefld[bx], 20h
inc bx
loop namebrk1
;比較字符串大小
mov cl,tel_count
lastp:
push cx
mov si,offset seanamefld
mov di,offset tel_tab ;+outputname*28
mov al,outputname
mov bl,28
mul bl
add di,ax
mov cx,20
cld
lastagain: cmpsb
jnz lastunmat
loop lastagain
;匹配成功
mov al,0
jmp lastoutput
lastunmat: mov al,-1
pop cx
inc outputname
loop lastp
lastoutput:
cmp al,0
jne noresult
mov cx,8
matchname:
mov dl,[di]
mov ah,02h
int 21h
inc di
loop matchname
jmp stop
noresult:
mov dx,offset string5
call print
stop:
MOV AH,4CH
INT 21H
;其他子程序
name_sort proc ;對名字和電話一起排序 ,待完成
push dx
push bx
push cx
push ax
mov dx,di
push di
sub dx,28 ;剛剛輸入的姓名的地址
lea bx,tel_tab
mov cl,tel_count
sortagain:
cmp bx,dx
je sortend
call strcompare
add bx,28
cmp al,1 ;如果剛剛輸入的姓名大,那就繼續循環
jne index1
loop sortagain
index1:
mov al,tel_count ;ax=(tel_count-cx)*28爲要放的單元數 ;如果小的話,把當前之後的名字後移28個字節,再把名字插入到當前位置
sub al,cl
mov ah,28
MUL ah
allmove:
call moveto28byte
sub dx,28
loop allmove
jmp putinto
putinto:
mov si,di ;剛剛輸入名字的新地址
lea di,tel_tab
add di,ax
mov cx,28
rep MOVSB
sortend:
pop di
pop ax
pop cx
pop bx
pop dx
ret
name_sort endp
moveto28byte proc ;dx爲當前地址28位各後移28個字節
push cx
push bx
push si
push di
mov bx,dx
add bx,28
mov si,dx
mov di,bx
mov cx,28
rep MOVSB
pop di
pop si
pop bx
pop cx
ret
moveto28byte endp
Inputname proc ;輸入名字
lea dx,tel_name
call cin
mov bl, namelen
mov cx, 20
sub cx, bx
namebrk: ;將人名除外所剩下的字符用空格填滿
mov namefld[bx], 20h
inc bx
loop namebrk
ret
Inputname endp
stor_name proc
inc tel_count
cld
mov si,offset tel_name+2
;mov di,offset tel_tab
mov cl,20
rep MOVSB
ret
stor_name endp
Inputtel proc
lea dx,tel_num
call cin
mov bl, numlen
mov cx, 8
sub cx, bx
numbrk: ;將人名除外所剩下的字符用空格填滿
mov numfld[bx], 20h
inc bx
loop numbrk
ret
Inputtel endp
stor_num proc
cld
lea si,numfld
;mov di,offset tel_tab
mov cl,8
rep MOVSB
ret
stor_num endp
;打印固定字符串,入口參數dx指向的地址以$符號結束
print proc
push ax
mov ah,09h
int 21h
pop ax
ret
print endp
;用戶輸入,入口參數dx指向第一個緩衝區地址
cin proc
push ax
mov ah,0AH
int 21h
pop ax
call printnewline
ret
cin endp
;輸出換行
printnewline proc
push ax
push dx
mov ah,02h
mov dl,0dh
int 21h
mov dl,0ah
int 21h
pop dx
pop ax
ret
printnewline endp
;字符串大小比較(字典序)
strcompare proc ;入口參數dx,bx的首地址,dx大於bx則輸出al爲1,否則爲0
push si
push di
push cx
mov si,dx
mov di,bx
push bx
push dx
mov cx,20
cld
stragain:
mov bl,[si]
cmp bl,[di]
jb unmat1
cmp bl,[di]
ja unmat2
inc si
inc di
loop stragain
unmat1: mov al,0
jmp endstrcompare
unmat2: mov al,1
endstrcompare:
pop dx
pop bx
pop cx
pop di
pop si
ret
strcompare endp
CODES ENDS
END START
輸出結果如圖: