鱼C论坛

 找回密码
 立即注册
查看: 921|回复: 0

[技术交流] 分享一个电话本程序

[复制链接]
发表于 2022-9-17 16:48:38 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
ReadAsm编写
  1. .386
  2. .model flat,stdcall
  3. option casemap:none

  4. include masm32rt.inc


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

  12.         ; ========= 常量 =========
  13.         ;输入格式:名称 电话号码
  14.         g_szScanFormat  BYTE   '%s %s',0h
  15.         ;输入格式:名称
  16.         g_szScanNameFormat BYTE   '%s',0h
  17.         ;打印格式:名称\t\t电话号
  18.         g_szPrintItemFormat BYTE   '姓名:%s',09h,09h,'电话:%s',0ah,0dh,0h
  19.         ;输入指令
  20.         g_szGetCmdFormat BYTE   '%d',0h

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

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

  45.         ; ========= 全局变量 =========
  46.         ;电话本
  47.         g_book PHONE 20 dup(<'0'>)
  48.         ;最大容量 最多保存20条记录
  49.         g_max dword 1 dup(20)
  50.         ;当前容量
  51.         g_nCount dword 1 dup(0)
  52.         ;单个电话本临时变量
  53.         g_tmpPhone PHONE <'0','0'>
  54.         ;当前用户选择的功能 1=查询 2=增加 3=删除 4=修改 5=看所有
  55.         g_nCmd byte 1 dup(0)
  56.         ;索引查找数
  57.         g_nI dword 1 dup(0)
  58.         ;临时指针
  59.         g_nTmp dword 1 dup(0)
  60.         ;找到了的索引
  61.         g_nFindIndex dword 1 dup(-1)
  62.         ;找到了的地址
  63.         g_nFindPoint dword 1 dup(0)
  64.        

  65. .code

  66. ; 打印菜单并接收用户指令到eax
  67. ; 功能 1=查询 2=增加 3=删除 4=修改
  68. SelectMenu proc
  69.         ; 清屏
  70.         push offset g_szClr
  71.         call crt_system
  72.         add esp,4
  73.         ; 打印菜单
  74.         push g_max
  75.         push g_nCount
  76.         push offset g_szMenu
  77.         call crt_printf
  78.         add esp,12
  79.         ; 用户输入指令,放入g_nCmd
  80.         push offset g_nCmd
  81.         push offset g_szCmdIn
  82.         call crt_scanf
  83.         add esp,8
  84.         ret

  85. SelectMenu endp

  86. ; 查找用户
  87. PhoneFind proc
  88.         ; 提示输入姓名
  89.         push offset g_szNameIn
  90.         call crt_printf
  91.         add esp,4
  92.         ; 用户输入姓名
  93.         lea eax,[g_tmpPhone + PHONE.m_name]
  94.         push eax
  95.         push offset g_szScanNameFormat
  96.         call crt_scanf
  97.         add esp,8
  98.         ; 重置i
  99.         mov g_nI,0 ; i = 0
  100. find_loop:
  101.         mov eax,g_nI
  102.         mov ebx,g_max ; max
  103.         cmp eax,ebx
  104.         ja find_empty ;i > g_max ,goto proc_end
  105.         ; 计算地址
  106.         imul eax,g_nI,sizeof(PHONE) ; i*单个元素大小 = 偏移地址给edi
  107.         lea edi,[g_book + eax] ; 电话本首地址 + 偏移地址 = 第i个元素的地址
  108.         lea edx,[edi] ; 保存第i个元素地址
  109.         mov g_nTmp, edx
  110.         ; 判断这个元素的姓名和输入的姓名是否匹配
  111.         lea esi,[g_tmpPhone + PHONE.m_name]
  112.         cmpsd dword ptr[edi + PHONE.m_name],dword ptr[esi]
  113.         jnz not_find
  114.         ; 找到了就输出信息
  115.         lea eax, [edx + PHONE.m_phone]
  116.         push eax
  117.         lea eax, [edx + PHONE.m_name]
  118.         push eax
  119.         push offset g_szPrintItemFormat
  120.         call crt_printf
  121.         add esp,12
  122.        
  123.         ; 记录索引
  124.         mov edx,g_nI
  125.         mov g_nFindIndex,edx
  126.         ; 记录地址
  127.         mov edx,g_nTmp
  128.         mov g_nFindPoint,edx
  129.        
  130.         ret
  131. not_find:
  132.         ; 没找到则继续找
  133.         inc g_nI ; i++
  134.         jmp find_loop
  135. find_empty:
  136.         ; 提示没有找到这条信息
  137.         push offset g_szErrNotFind
  138.         call crt_printf
  139.         add esp,4
  140.        
  141.         mov g_nFindIndex,-1 ; 没找到 索引为-1
  142.         mov g_nFindPoint,0 ; 没找到 地址为0
  143.         ret

  144. PhoneFind endp

  145. ; 增加用户
  146. PhoneAdd proc
  147.         ;判断容量是否满了
  148.         mov eax,g_nCount
  149.         mov ebx,g_max
  150.         cmp eax,ebx
  151.         jb phone_insert
  152.         ; 如果容量满了输出提示
  153.         push offset g_szErrMax
  154.         call crt_printf
  155.         add esp,4
  156.         ret
  157. phone_insert:
  158.         ; 计算地址
  159.         mov ecx,g_nCount  ; 当前容量
  160.         imul eax,ecx,sizeof(PHONE) ; i*单个元素大小 = 偏移地址给edi
  161.         lea edi,[g_book + eax] ; 电话本首地址 + 偏移地址 = 第i个元素的地址
  162.        
  163.         ; 提示输入姓名
  164.         push offset g_szNameIn
  165.         call crt_printf
  166.         add esp,4
  167.         ; 用户输入姓名
  168.         lea eax,[edi + PHONE.m_name]
  169.         push eax
  170.         push offset g_szScanNameFormat
  171.         call crt_scanf
  172.         add esp,8
  173.        
  174.         ; 提示输入电话
  175.         push offset g_szPhoneNumberIn
  176.         call crt_printf
  177.         add esp,4
  178.         ; 用户输入电话
  179.         lea eax,[edi + PHONE.m_phone]
  180.         push eax
  181.         push offset g_szScanNameFormat
  182.         call crt_scanf
  183.         add esp,8
  184.         ; 当前容量+1
  185.         inc g_nCount
  186.         ; 插入成功
  187.         push offset g_szTipsAdd
  188.         call crt_printf
  189.         add esp,4
  190.         ret

  191. PhoneAdd endp

  192. ; 删除用户
  193. PhoneDel proc
  194.         ; 寻找用户
  195.         call PhoneFind
  196.         cmp g_nFindIndex, -1
  197.         je find_empty; 没有此用户
  198.         ; 找到了用户后,第i个后面依次往前移动
  199.        
  200.         ; 循环次数 = 总容量 - 找到的索引
  201.         ; 若找到的索引i=3 ,总容量max = 5, 5-3=2次,索引从0开始,即 3覆盖2,  4覆盖3
  202.         mov ecx, g_max         ;总容量
  203.         mov eax, g_nFindIndex  ;找到的数据,索引从0开始
  204.         sub ecx, eax           ;循环次数
  205.        
  206. copy_loop:
  207.         ; copy到当前容量后还没到Max需要提前结束循环
  208.         ; 即 g_nFindIndex >= g_nCount 退出
  209.         mov eax,g_nFindIndex
  210.         mov ebx,g_nCount
  211.         cmp eax, ebx
  212.         jnb copy_over ; 提前结束

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

  219.         ; PHONE类型刚好为16字节 也就是4次movsd就能实现拷贝了
  220.         ; 保存外层 ecx
  221.         push ecx
  222.         ; 循环4次
  223.         mov ecx,4
  224. copy_item:
  225.         mov edi,g_nTmp
  226.         mov esi,edi
  227.         imul eax, ecx, 4
  228.         lea edi,[edi + eax - 4]
  229.         lea esi,[eax + esi + sizeof(PHONE) -4]
  230.         movsd dword ptr[edi], dword ptr[esi]
  231.         loop copy_item
  232.         ; 内层循环完毕,还原ecx
  233.         pop ecx
  234.         ; 复制一次,寻找索引+1
  235.         inc g_nFindIndex
  236.         loop copy_loop ; 循环ecx次
  237. copy_over:
  238.         ; 当前容量 - 1
  239.         dec g_nCount
  240.         ; 删除成功
  241.         push offset g_szTipsDel
  242.         call crt_printf
  243.         add esp,4
  244. find_empty:
  245.         ret

  246. PhoneDel endp

  247. ; 修改用户
  248. PhoneUpdate proc
  249.         ; 寻找用户
  250.         call PhoneFind
  251.         cmp g_nFindIndex, -1
  252.         je find_empty; 没有此用户

  253.         ; 找到了 这个用户 进行数据更新
  254.         ; 提示输入姓名
  255.         push offset g_szNewNameIn
  256.         call crt_printf
  257.         add esp,4
  258.         ; 用户输入新的姓名
  259.         mov edx,g_nFindPoint
  260.         lea eax,[edx + PHONE.m_name]
  261.         push eax
  262.         push offset g_szScanNameFormat
  263.         call crt_scanf
  264.         add esp,8
  265.         ; 提示输入电话
  266.         push offset g_szNewPhoneNumberIn
  267.         call crt_printf
  268.         add esp,4
  269.         ; 用户输入新的电话
  270.         mov edx,g_nFindPoint
  271.         lea eax,[edx + PHONE.m_phone]
  272.         push eax
  273.         push offset g_szScanNameFormat
  274.         call crt_scanf
  275.         add esp,8
  276.        
  277.         ; 输出提示 修改成功
  278.         push offset g_szTipsUpdate
  279.         call crt_printf
  280.         add esp,4
  281.        
  282. find_empty:
  283.         ret

  284. PhoneUpdate endp

  285. ; 打印所有用户
  286. PhoneShowAll proc
  287.         mov g_nI,0
  288. print_loop:
  289.         mov eax,g_nI
  290.         cmp eax,g_nCount
  291.         ; i<g_nCount 则打印
  292.         jb print
  293.         push offset g_szTipsNoMore
  294.         call crt_printf
  295.         add esp,4
  296.         ret
  297. print:
  298.         ; 计算地址
  299.         imul eax,g_nI,sizeof(PHONE) ; i*单个元素大小 = 偏移地址给edi
  300.         lea edi,[g_book + eax] ; 电话本首地址 + 偏移地址 = 第i个元素的地址
  301.        
  302.         ; 打印信息
  303.         lea eax, [edi + PHONE.m_phone]
  304.         push eax
  305.         lea eax, [edi + PHONE.m_name]
  306.         push eax
  307.         push offset g_szPrintItemFormat
  308.         call crt_printf
  309.         add esp,12       
  310.         inc g_nI
  311.         jmp print_loop


  312. PhoneShowAll endp


  313. main:
  314.         ; 打印菜单获取用户指令
  315.         call SelectMenu
  316.         cmp g_nCmd, 1
  317.         jne menu_add; 输入的是1(查询)继续执行,否则跳到下一个判断
  318.         call PhoneFind
  319.         jmp menu_end
  320. menu_add:
  321.         cmp g_nCmd, 2
  322.         jne menu_del ; 输入的是2(增加)继续执行,否则跳到下一个判断
  323.         call PhoneAdd
  324.         jmp menu_end
  325. menu_del:       
  326.         cmp g_nCmd, 3
  327.         jne menu_update ; 输入的是3(删除)继续执行,否则跳到下一个判断
  328.         call PhoneDel
  329.         jmp menu_end
  330. menu_update:       
  331.         cmp g_nCmd, 4
  332.         jne menu_showall ; 输入的是4(修改)继续执行,否则跳到下一个判断
  333.         call PhoneUpdate
  334.         jmp menu_end
  335. menu_showall:
  336.         cmp g_nCmd, 5
  337.         jne menu_unknow ; 输入的是5(查看所有)继续执行,否则跳到下一个判断
  338.         call PhoneShowAll
  339.         jmp menu_end
  340. menu_unknow: ; 输入的未知指令
  341.         push offset g_szErrUnknowCmd
  342.         call crt_printf
  343.         add esp,4
  344. menu_end: ; 执行完毕返回菜单
  345.         push offset g_szPause
  346.         call crt_system
  347.         add esp,4
  348.         jmp main
  349. quit: ; 退出
  350.         ret

  351. end main

  352. end
复制代码



                               
登录/注册后可看大图

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-28 17:38

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表