彙編原理實驗 --電話簿的實現

實驗4:(電話本)

要求:

可放50項的電話號碼錶,每項中有姓名(20)和電話號碼(8),存放聯繫人,並且進行排序。並完成添加電話,根據姓名查詢電話,顯示輸出等功能

算法設計:

①數據結構:可放50項的電話號碼錶,每項中有姓名(20)和電話號碼(8)。數據定義則用tel_tab  db 50 dup(20 dup(' '),8 dup(' ')),即可滿足,每項用空白符初始化

②.1存放輸入的數據:tel_nametel_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
輸出結果如圖:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章