8086系列(18):查找电话号码

题目

1.题目:查找电话号码phone
2.实验要求:
(1)建立一个可存放50项的电话号码表,每项包括任命(20个字符)及电话号码(8个字符)两部分;
(2)程序可接收输入人名及相应的电话号码,并把它们加入电话号码表中;
(3)凡有新的输入后,程序应按照人名对电话号码表重新排序;
(4)程序可接收需要查找电话号码的人名,并从电话号码表中查出其电话号码,再在屏幕上以如下格式显示出来。

name tel.
××× ×××
3.提示:程序采用子程序结构。主程序的部分主要如下:

显示提示符‘Input name’
调用子程序’input_name’接收人名
调用子程序stor_name把人名存入电话号码表tel_tab中
显示提示符’Input a telephone number:’
调用子程序inphone接收电话号码,并把它存入电话号码表tel_tab中
如果输入已经结束,则调用name_sort子程序对电话号码表按人名排序
显示提示符’Do you want a telephone number?’
回答N则退出程序
回答Y则再显示提示符‘name?’
调用子程序input_name接收人名
调用子程序name_search再电话号码表中查询所需的电话号码
调用子程序printline按要求格式显示人名和电话号码
重复查号提示符直至用户不再要求查找为止

思路

大致画了以下流程图,并指明了主程序和子程序相互传递参数之间的方式
在这里插入图片描述
程序较为复杂,设计到了串转移和串查找指令,程序的核心功能是name_sort排序和name_search查找功能。name_sort使用了冒泡排序,但又不是经典的冒泡排序,为了程序简单,每次都从头到尾开始比较,把原本的比较次数(N)*(N-1)变为了N * N,并设置交换位swapped来判断是否结束排序。name_search要用到cmpsw指令,找到后把他放入temp临时变量中之后传递给Printline,没找到通过cx=-1传递给print_line。
以下是name_sort 和 name_search的空间地址结构:

在这里插入图片描述
还有一个坑就是在定义缓冲区长度时应该把回车的长度加进去,否则可能造成覆盖的错误。

在这里插入图片描述
总体来说,程序极为麻烦,调试极其不易。

代码

;--------数据段开始----------
datasg segment
    namepar label byte   ;接受名字输入
    maxnlen db 21
    actnlen db ?
    _name db 21 dup(?)

    phonepar label byte  ;接受电话号码输入
    maxplen db 9
    actplen db ?
    phone db 9 dup(?)

    crlf db 13,10,'$'     ;回车换行
    endaddr dw ?
    mess1 db 'Input name:','$'
    mess2 db 'Input a telephone number:','$'
    mess3 db 'Do you want a telephone number:','$'
    mess4 db 'name?','$'
    mess5 db 'name',16 dup(' '),'tel',0dh,0ah,'$'
    mess6 db 'Not in the table.',0dh,0ah,'$'
    mess7 db 'Invalid input!',0dh,0ah,'$'
    count db 0
    tel_tab db 50 dup(20 dup(' ')),8 dup(' ')   ;电话号码表
    temp db 20 dup(' '),8 dup(' '),0dh,0ah,'$'  ;暂存的tel_tab项
    swapped db 0 
datasg ends
;--------代码段开始---------
codesg segment
main proc far
    assume cs:codesg,ds:datasg,es:datasg
start:
    push ds
    sub ax,ax
    push ax
    mov ax,datasg
    mov ds,ax
    mov es,ax
    ;;;;;;;;;;;;;;;
    cld            ;方向标志位置0
    lea di,tel_tab  ;目的变址指针指向tel_tab,为了之后搬入tel_tab
inputloop:
    mov ah,09h     ;提示'Input name'
    lea dx,mess1
    int 21h
    call input_name
    cmp actnlen,0   ;输入长度小于1,都将直接终止输入
    jz a10
    cmp count,50    ;如果超过50个号码
    je a10
    call stor_name

    mov ah,09h    ;提示'Input a telephone number'
    lea dx,mess2
    int 21h
    call inphone
    jmp inputloop
a10:
    cmp count,1
    jbe searchloop  ;count<=1 直接跳去查找
    call name_sort  ;否则就要排序
searchloop:
    lea dx,mess3  ;提示‘Do you want a telephone number:’
    mov ah,09
    int 21h
    mov ah,01h   ;输入字符判断y or n
    int 21h
    cmp al,'N'
    je exit
    cmp al,'n'
    je exit
    cmp al,'Y'
    je showname
    cmp al,'y'
    je showname
    mov ah,09      ;回车换行
    lea dx,crlf
    int 21h
    lea dx,mess7   ;如果不是Yes or No 否则提示'Invalid input!''
    mov ah,09
    int 21h
    jmp searchloop  ;反复询问
showname:
    mov ah,09      ;回车换行
    lea dx,crlf
    int 21h
    lea dx,mess4    ;提示'name?''
    mov ah,09
    int 21h
    call input_name
    call name_search
    call printline
    jmp searchloop   ;反复询问
exit:
    ret
main endp
;-------input_name子程序开始-----
;这里不需要保护寄存器,采用直接地址法传递参数
input_name proc near
    mov ah,0ah    ;调用0a号中断输入到缓冲区
    lea dx,namepar  ;ds:dx 为缓冲区首地址
    int 21h
    mov ah,02h    ;换行
    mov dl,0ah
    int 21h

    mov bh,0
    mov bl,actnlen   ;bx存放name的长度
    mov cx,20
    sub cx,bx     ;cx剩余长度
i20:              ;填充空格字段
    mov _name[bx],20h
    inc bx
    loop i20
    ret
input_name endp
;---------stor_name子程序开始-------
;这里不需要保护寄存器,采用直接地址法传递参数
stor_name proc near
    inc count
    cld    
    lea si,_name  ;将20个字节的name搬入tel_phone
    mov cx,10        
    rep movsw
    ret
stor_name  endp  
;----------inphone子程序开始--------
;这里不需要保护寄存器,采用直接地址法传递参数
inphone proc near
    mov ah,0ah    ;调用0a号中断输入到缓冲区
    lea dx,phonepar  ;ds:dx 为缓冲区首地址
    int 21h
    mov ah,02h   ;换行
    mov dl,0ah
    int 21h

    mov bh,0
    mov bl,actplen
    mov cx,9
    sub cx,bx
is20:      ;填充空格字段
    mov phone[bx],20h
    inc bx 
    loop is20

    cld    ;清理方向标志位
    lea si,phone   ;将8位phone搬入tel_phone
    mov cx,4
    rep movsw   
    ret
inphone endp
;--------name_sort子程序开始--------
;这里不需要保护寄存器,采用直接地址法传递参数
;冒泡排序
name_sort proc near
    sub di,56    ;tel_lab  20 + 8
    mov endaddr,di  ;endaddr指向最后第二个tel_lab项的首地址
ns10:
    mov swapped,0   ;没有交换过
    lea si,tel_tab  ;si指向tel_lab的首地址
ns20:
    mov cx,20       ;20个长度的name
    mov di,si       
    add di,28
    mov ax,di
    mov bx,si
    repe cmpsb
    jbe ns30        ;如果tel_tab[i]<tel_tab[i+1] 不用交换
    call npxchg
ns30:
    mov si,ax
    cmp si,endaddr   ;一轮比较后,最大的已经排到了最后面
    jbe ns20
    cmp swapped,0   ;如果交换过,则需要再次比较

    ; mov di,endaddr  ;endaddr - 28  代表最后一个已经比较完成
    ; sub di,28
    ; mov endaddr,di

    jnz ns10 
    ret  
name_sort endp
;;;;;;;;;;;;;;;;;;;;
;bx 和 ax 寄存器传递参数u
;tel_tab[i]和tel_tab[i+1]交换
npxchg proc near
    mov cx,14     ;temp = a[i]
    lea di,temp
    mov si,bx
    rep movsw

    mov cx,14     ;a[i+1] = a[i]
    mov di,bx
    rep movsw

    mov cx,14     ;a[i] = temp
    lea si,temp
    rep movsw
    mov swapped,1   ;swapped
    ret
npxchg endp
;--------name_search子程序开始-----
name_search proc near
    lea si,tel_tab    ;源变址指针si ->tel_tab
    mov bx,si
    add endaddr,28
nase10:
    lea di,_name     ;目的变址指针di ->_name
    mov cx,10        ;name长度20 db
    repe cmpsw
    jcxz nase_exit   ;如果找到

    add bx,28        ;si+28  ,并用bx暂存
    mov si,bx        
    cmp si,endaddr   ;比较是否查到末尾了
    jbe nase10       ;还未到最后一个则继续查找
notintab:
    mov cx,-1        ;没有找到让cx=-1
    ret
nase_exit:
    mov si,bx       ;则搬入temp
    lea di,temp
    mov cx,14
    rep movsw
    ret
name_search endp
;-------printline子程序开始----
printline  proc  near
    cmp     cx,-1     
    je     norecord    ;没有找到
    mov     ah,09h     ;提示'name',16 dup(' '),'tel',0dh,0ah,'$' 标题栏
    lea     dx,mess5
    int     21h
    mov     ah,09h   
    lea     dx,temp    ;输入暂存temp的tel_tab项
    int     21h
    ret
norecord:
    mov     ah,09h    ;提示'Not in the table.'
    lea     dx,mess6
    int     21h          
    ret
printline  endp 
codesg ends
end start

结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值