【汇编】电话本

.386
.model flat,stdcall
option casemap:none

include masm32rt.inc


.data
	; ========= 结构体 ========= 
	;电话本-成员
	PHONE struct
	    m_name byte 8 dup(0)   ;姓名
	    m_phone byte 8 dup(0)  ;电话
	PHONE ends

	; ========= 常量 ========= 
	;输入格式:名称 电话号码
	g_szScanFormat  BYTE   '%s %s',0h
	;输入格式:名称
	g_szScanNameFormat BYTE   '%s',0h
	;打印格式:名称\t\t电话号
	g_szPrintItemFormat BYTE   '姓名:%s',09h,09h,'电话:%s',0ah,0dh,0h
	;输入指令
	g_szGetCmdFormat BYTE   '%d',0h

	;菜单
	g_szMenu db "电话本",0ah,0dh,
	"1=查询",0ah,0dh,
	"2=增加",0ah,0dh,
	"3=删除",0ah,0dh,
	"4=修改",0ah,0dh,
	"5=查看所有",0ah,0dh,
	"当前储存了 %d / %d 条信息",0ah,0dh,
	">>",0h

	g_szClr    BYTE   'cls',0h
	g_szPause   BYTE   'pause',0h
	g_szCmdIn   BYTE '%d',0h
	g_szNameIn   BYTE   '输入姓名:',0h
	g_szNewNameIn   BYTE   '输入新的姓名:',0h
	g_szPhoneNumberIn BYTE   '请输入电话号码:',0h
	g_szNewPhoneNumberIn BYTE   '请输入新的电话号码:',0h
	g_szTab  BYTE    0dh,0ah,0h ;换行回车\r\n
	g_szTipsDel  BYTE   '<已删除这条信息>',0dh,0ah,0h
	g_szTipsAdd   BYTE   '<插入成功>',0dh,0ah,0h
	g_szTipsUpdate   BYTE   '<修改成功>',0dh,0ah,0h
	g_szTipsNoMore   BYTE   '<没有更多信息>',0dh,0ah,0h
	g_szErrNotFind   BYTE   '<没有这条信息>',0dh,0ah,0h
	g_szErrMax   BYTE   '<电话本储存满了>',0dh,0ah,0h
	g_szErrUnknowCmd BYTE '<未知指令>',0dh,0ah,0h

	; ========= 全局变量 ========= 
	;电话本
	g_book PHONE 20 dup(<'0'>)
	;最大容量 最多保存20条记录
	g_max dword 1 dup(20) 
	;当前容量
	g_nCount dword 1 dup(0)
	;单个电话本临时变量
	g_tmpPhone PHONE <'0','0'>
	;当前用户选择的功能 1=查询 2=增加 3=删除 4=修改 5=看所有
	g_nCmd byte 1 dup(0)
	;索引查找数
	g_nI dword 1 dup(0)
	;临时指针
	g_nTmp dword 1 dup(0)
	;找到了的索引
	g_nFindIndex dword 1 dup(-1)
	;找到了的地址
	g_nFindPoint dword 1 dup(0)
	

.code

; 打印菜单并接收用户指令到eax
; 功能 1=查询 2=增加 3=删除 4=修改
SelectMenu proc
	; 清屏
	push offset g_szClr
	call crt_system
	add esp,4
	; 打印菜单
	push g_max
	push g_nCount
	push offset g_szMenu
	call crt_printf
	add esp,12
	; 用户输入指令,放入g_nCmd
	push offset g_nCmd
	push offset g_szCmdIn
	call crt_scanf
	add esp,8
	ret

SelectMenu endp

; 查找用户
PhoneFind proc
	; 提示输入姓名
	push offset g_szNameIn
	call crt_printf
	add esp,4
	; 用户输入姓名
	lea eax,[g_tmpPhone + PHONE.m_name]
	push eax
	push offset g_szScanNameFormat
	call crt_scanf
	add esp,8
	; 重置i
	mov g_nI,0 ; i = 0
find_loop:
	mov eax,g_nI
	mov ebx,g_max ; max
	cmp eax,ebx
	ja find_empty ;i > g_max ,goto proc_end
	; 计算地址
	imul eax,g_nI,sizeof(PHONE) ; i*单个元素大小 = 偏移地址给edi
	lea edi,[g_book + eax] ; 电话本首地址 + 偏移地址 = 第i个元素的地址
	lea edx,[edi] ; 保存第i个元素地址
	mov g_nTmp, edx
	; 判断这个元素的姓名和输入的姓名是否匹配
	lea esi,[g_tmpPhone + PHONE.m_name]
	cmpsd dword ptr[edi + PHONE.m_name],dword ptr[esi]
	jnz not_find
	; 找到了就输出信息
	lea eax, [edx + PHONE.m_phone]
	push eax
	lea eax, [edx + PHONE.m_name]
	push eax
	push offset g_szPrintItemFormat
	call crt_printf
	add esp,12
	
	; 记录索引
	mov edx,g_nI
	mov g_nFindIndex,edx
	; 记录地址
	mov edx,g_nTmp
	mov g_nFindPoint,edx
	
	ret
not_find:
	; 没找到则继续找
	inc g_nI ; i++
	jmp find_loop
find_empty:
	; 提示没有找到这条信息
	push offset g_szErrNotFind
	call crt_printf
	add esp,4
	
	mov g_nFindIndex,-1 ; 没找到 索引为-1
	mov g_nFindPoint,0 ; 没找到 地址为0
	ret

PhoneFind endp

; 增加用户
PhoneAdd proc
	;判断容量是否满了
	mov eax,g_nCount
	mov ebx,g_max
	cmp eax,ebx
	jb phone_insert
	; 如果容量满了输出提示
	push offset g_szErrMax
	call crt_printf
	add esp,4
	ret
phone_insert:
	; 计算地址
	mov ecx,g_nCount  ; 当前容量
	imul eax,ecx,sizeof(PHONE) ; i*单个元素大小 = 偏移地址给edi
	lea edi,[g_book + eax] ; 电话本首地址 + 偏移地址 = 第i个元素的地址
	
	; 提示输入姓名
	push offset g_szNameIn
	call crt_printf
	add esp,4
	; 用户输入姓名
	lea eax,[edi + PHONE.m_name]
	push eax
	push offset g_szScanNameFormat
	call crt_scanf
	add esp,8
	
	; 提示输入电话
	push offset g_szPhoneNumberIn
	call crt_printf
	add esp,4
	; 用户输入电话
	lea eax,[edi + PHONE.m_phone]
	push eax
	push offset g_szScanNameFormat
	call crt_scanf
	add esp,8
	; 当前容量+1
	inc g_nCount 
	; 插入成功
	push offset g_szTipsAdd
	call crt_printf
	add esp,4
	ret

PhoneAdd endp

; 删除用户
PhoneDel proc
	; 寻找用户
	call PhoneFind
	cmp g_nFindIndex, -1
	je find_empty; 没有此用户
	; 找到了用户后,第i个后面依次往前移动
	
	; 循环次数 = 总容量 - 找到的索引
	; 若找到的索引i=3 ,总容量max = 5, 5-3=2次,索引从0开始,即 3覆盖2,  4覆盖3
	mov ecx, g_max         ;总容量
	mov eax, g_nFindIndex  ;找到的数据,索引从0开始
	sub ecx, eax           ;循环次数
	
copy_loop:
	; copy到当前容量后还没到Max需要提前结束循环
	; 即 g_nFindIndex >= g_nCount 退出
	mov eax,g_nFindIndex
	mov ebx,g_nCount
	cmp eax, ebx
	jnb copy_over ; 提前结束

	mov eax, g_nFindIndex  ;找到的数据,索引从0开始
	; 计算i元素地址 = 电话本首地址 + 找到的索引 * 一个元素大小
	imul esi, eax, sizeof(PHONE)
	lea edi, [g_book + esi]        ; i元素地址
	;lea esi, [edi + sizeof(PHONE)] ; i下一个元素地址
	mov g_nTmp, edi

	; PHONE类型刚好为16字节 也就是4次movsd就能实现拷贝了
	; 保存外层 ecx
	push ecx
	; 循环4次
	mov ecx,4
copy_item:
	mov edi,g_nTmp
	mov esi,edi
	imul eax, ecx, 4
	lea edi,[edi + eax - 4]
	lea esi,[eax + esi + sizeof(PHONE) -4]
	movsd dword ptr[edi], dword ptr[esi]
	loop copy_item
	; 内层循环完毕,还原ecx
	pop ecx
	; 复制一次,寻找索引+1
	inc g_nFindIndex
	loop copy_loop ; 循环ecx次
copy_over:
	; 当前容量 - 1
	dec g_nCount
	; 删除成功
	push offset g_szTipsDel
	call crt_printf
	add esp,4
find_empty:
	ret

PhoneDel endp

; 修改用户
PhoneUpdate proc
	; 寻找用户
	call PhoneFind
	cmp g_nFindIndex, -1
	je find_empty; 没有此用户

	; 找到了 这个用户 进行数据更新
	; 提示输入姓名
	push offset g_szNewNameIn
	call crt_printf
	add esp,4
	; 用户输入新的姓名
	mov edx,g_nFindPoint
	lea eax,[edx + PHONE.m_name]
	push eax
	push offset g_szScanNameFormat
	call crt_scanf
	add esp,8
	; 提示输入电话
	push offset g_szNewPhoneNumberIn
	call crt_printf
	add esp,4
	; 用户输入新的电话
	mov edx,g_nFindPoint
	lea eax,[edx + PHONE.m_phone]
	push eax
	push offset g_szScanNameFormat
	call crt_scanf
	add esp,8
	
	; 输出提示 修改成功
	push offset g_szTipsUpdate
	call crt_printf
	add esp,4
	
find_empty:
	ret

PhoneUpdate endp

; 打印所有用户
PhoneShowAll proc
	mov g_nI,0
print_loop:
	mov eax,g_nI
	cmp eax,g_nCount
	; i<g_nCount 则打印
	jb print
	push offset g_szTipsNoMore
	call crt_printf
	add esp,4
	ret
print:
	; 计算地址
	imul eax,g_nI,sizeof(PHONE) ; i*单个元素大小 = 偏移地址给edi
	lea edi,[g_book + eax] ; 电话本首地址 + 偏移地址 = 第i个元素的地址
	
	; 打印信息
	lea eax, [edi + PHONE.m_phone]
	push eax
	lea eax, [edi + PHONE.m_name]
	push eax
	push offset g_szPrintItemFormat
	call crt_printf
	add esp,12	
	inc g_nI
	jmp print_loop


PhoneShowAll endp


main:
	; 打印菜单获取用户指令
	call SelectMenu
	cmp g_nCmd, 1
	jne menu_add; 输入的是1(查询)继续执行,否则跳到下一个判断
	call PhoneFind
	jmp menu_end
menu_add:
	cmp g_nCmd, 2
	jne menu_del ; 输入的是2(增加)继续执行,否则跳到下一个判断
	call PhoneAdd
	jmp menu_end 
menu_del:	
	cmp g_nCmd, 3
	jne menu_update ; 输入的是3(删除)继续执行,否则跳到下一个判断
	call PhoneDel
	jmp menu_end
menu_update:	
	cmp g_nCmd, 4
	jne menu_showall ; 输入的是4(修改)继续执行,否则跳到下一个判断
	call PhoneUpdate
	jmp menu_end 
menu_showall:
	cmp g_nCmd, 5
	jne menu_unknow ; 输入的是5(查看所有)继续执行,否则跳到下一个判断
	call PhoneShowAll
	jmp menu_end 
menu_unknow: ; 输入的未知指令
	push offset g_szErrUnknowCmd
	call crt_printf
	add esp,4
menu_end: ; 执行完毕返回菜单
	push offset g_szPause
	call crt_system
	add esp,4
	jmp main
quit: ; 退出
	ret

end main

end

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值