汇编原理实验 --电话簿的实现

实验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
输出结果如图:

汇编原理实验 --电话簿的实现_第1张图片

你可能感兴趣的:(算法,汇编原理)