彙編寫的電話本

頭文件

.data
;定義結構體
CONTACTSSTRUCT struct
    ;名字
    szName BYTE 25 dup (0)
    ;電話號碼
    szPhNumber BYTE 12 dup(0)
CONTACTSSTRUCT ends
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;struct *pstruct
PCONTACTSSTRUCT TYPEDEF PTR CONTACTSSTRUCT
;聲明全局變量
;定義結構體數組
g_stContacts CONTACTSSTRUCT 100 dup(<'0'>)
g_nCountMax DWORD 100 ;最大存放元素
g_strTemContacts CONTACTSSTRUCT <'0','0'> ;接收輸入信息
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
g_szOK BYTE 'OK',0

g_start1 BYTE ' 1.添加用戶',0ah,0dh,0
g_start2 BYTE '2.刪除用戶',0ah,0dh,0
g_start3 BYTE '3.修改用戶',0ah,0dh,0
g_start4 BYTE '4.查找用戶',0ah,0dh,0
g_start7 BYTE '5.所有用戶',0ah,0dh,0
g_start5 BYTE '請輸入選項查:',0

g_szstartFormat BYTE '%s %s %s %s %s %s',0
;錯誤提示
g_start6 BYTE '輸入錯誤請重新輸入!!!',0
g_szstart6Format BYTE '%s',0ah,0dh,0
;用於接收
g_num DWORD 0
g_szstart7Format BYTE '%d',0
;addfunc
g_szAddStr BYTE '請輸入用戶名密碼格式如:allen 123',0ah,0dh,0
g_szretur BYTE '增加成功!!!',0ah,0dh,0
;removefunc
g_szremoveAddStr BYTE '請輸入要刪除的用戶名如:allen ',0ah,0dh,0
g_szremoveretur BYTE '刪除操作完畢!!!',0ah,0dh,0
g_szremovenot BYTE '沒有,刪除失敗!!!',0ah,0dh,0
;changefunc ModifyData
;定義格式控制符 
g_szScanfFormat BYTE '%s %s',0
g_szchangeAddStr BYTE '請輸入要修改的用戶名如:allen ',0ah,0dh,0
g_szchangeAdd BYTE '%s',0
g_szchangeretur BYTE '修改完畢!!!',0ah,0dh,0
g_szchangernot BYTE '沒有,修改失敗!!!',0ah,0dh,0
g_szchange BYTE '請輸入用戶名密碼格式如:allen 123',0ah,0dh,0
;checkfunc
g_szcheckAddStr BYTE '請輸入要查找的用戶名如:allen ',0ah,0dh,0
g_szcheck BYTE '沒找到!!!',0ah,0dh,0
;接收一個名字
g_szScanName BYTE '%s',0   ;輸入這裏不通用這種方式0ah,0dh,0
;輸出一個密碼
g_szScanPasswd BYTE '%s',0ah,0dh,0 

;元素個數
g_nCount DWORD 0
g_szCount BYTE '當前總個數%d',0ah,0dh,0 

;FindDataAll
g_szFindDataAll BYTE '%s----%s',0ah,0dh,0 
g_szcheckretur BYTE '查詢一條完畢!!!',0ah,0dh,0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

main函數

.386
.model flat,stdcall
option casemap:none
include passwd.Inc
include msvcrt.inc ;c函數頭文件
includelib msvcrt.lib;c函數庫
include kernel32.inc
includelib kernel32.lib
;這裏都是用的全局要清理 
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ;push ebx
    ;mov ebx,sizeof(CONTACTSSTRUCT)
    ;push ebx
    ;push 0
    ;push edi
    ;call crt_memset
    ;add esp,12
    ;pop ebx
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;添加用戶信息
ADD_USER proc ;無參數
    pushad ;全部入棧
;----------------------------------------------------------------
    lea eax,g_szAddStr 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
    lea esi,[g_stContacts];保存數據的結構體數組
    mov ecx,g_nCount;獲取當前已經插入的用戶個數
    mov eax,sizeof(CONTACTSSTRUCT) ;計算大小
    imul eax,ecx
    add esi,eax ;移動結構體數組的指針(用戶個數*結構體的大小)
    lea eax,[esi+CONTACTSSTRUCT.szPhNumber] ;電話號碼
    lea edx,[esi+CONTACTSSTRUCT.szName] ;用戶名
    push eax
    push edx
    push offset g_szScanfFormat ;g_szScanfFormat BYTE '%s %s',0
    call crt_scanf
    add esp,12
    ;元素個數
    ;g_nCount DWORD 0
    inc g_nCount 
;----------------------------------------------------------------
        lea eax,g_szretur   ;g_szretur BYTE '增加成功!!!',0ah,0dh,0
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
    popad ;全部出棧 
    ret
ADD_USER endp
;查詢用戶信息
FindData proc
    pushad ;全部入棧
    lea eax,g_szcheckAddStr 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
;----------------------------------------------------------------
    ;1.輸入數據 
    ;定義結構體數組
    ;接收用戶名
    lea edi,[g_strTemContacts.szName];保存結構體中名字的地址
    push edi
    ;g_szScanName BYTE '%s',0
    push offset g_szScanName 
    call crt_scanf
    add esp,8
    ;開始查詢
    mov ecx,0 ;初始化循環次數(默認從0開始循環)
CYCLE_MARK:   ;標號
    cmp ecx,g_nCount
    ;如果相等就說明沒有數據了
    je allennot     ;ret
    mov eax,sizeof(CONTACTSSTRUCT) ;計算大小
    imul eax,ecx               ;相乘
    ;2.1根據ecx的值找到下一個結構體名字數組的地址
    lea esi,[g_stContacts] ;保存數據的結構體數組首地址
    add esi,eax        ;偏移
    lea edi,[g_strTemContacts.szName];剛輸入的名字的地址
    ;2.2比較字符串
    mov eax,ecx ;保存外層循環的次數
    mov ecx,6 ;初始化串操作循環次數(4字節比較)   4*6=24  加上最後一個==25
    repe cmpsd dword ptr [esi],dword ptr [edi] ;查看repe系列指令的使用原理
    je CARRIEDOUT_MAKR  ;如果找到則跳轉(轉出信息)  
    mov ecx,eax         ;如果沒有  還原ecx    
    inc ecx             ;循環次數加1
    jmp CYCLE_MARK      ;無條件跳轉到外層循環開始位置
CARRIEDOUT_MAKR:
    ;輸出信息
    mov ecx,eax     ;先還原ecx
    lea esi,[g_stContacts]
    mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小 
    imul ebx,ecx
    add esi,ebx
    lea eax,[esi+CONTACTSSTRUCT.szPhNumber] ;電話號碼
    push eax
    push offset g_szScanPasswd
    call crt_printf
    add esp,8
    ;輸出完成退出
    jmp allenretn
;----------------------------------------------------------------
allennot:           ;沒有
    lea eax,g_szcheck 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
    popad ;全部出棧 
    ret
allenretn:          ;找到了
    lea eax,g_szcheckretur 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
    popad ;全部出棧 
    ret
FindData endp

;查看所有信息
FindDataAll proc
    pushad ;全部入棧
;----------------------------------------------------------------
    ;開始查詢
    ;i=0
    mov ecx,0 ;初始化循環次數(默認從0開始循環)
    lea esi,[g_stContacts] ;保存數據的結構體數組
CYCLE_MARK:   ;標號
    cmp ecx,g_nCount
    ;如果相等就說明沒有數據了
     je allenretn     ;ret
    mov eax,sizeof(CONTACTSSTRUCT) ;計算大小
    imul eax,ecx
    ;2.1根據ecx的值找到下一個結構體名字數組的地址
    add esi,eax
    push ecx ;保存ecx

    lea edx,[esi+CONTACTSSTRUCT.szName];當前結構體在數組中的首地址
    lea ebx,[esi+CONTACTSSTRUCT.szPhNumber];加上名字偏移就是電話了
    push ebx  
    push edx
    push offset g_szFindDataAll  ;g_szFindDataAll BYTE '%s----%d',0ah,0dh,0 
    call crt_printf
    add esp,12

    ;還原ecx
    pop ecx
    inc ecx  ;++i
    jmp CYCLE_MARK
;----------------------------------------------------------------
allenretn:
    lea eax,g_szcheckretur 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
    popad ;全部出棧 
    ret
FindDataAll endp
;修改用戶信息
ModifyData proc
    pushad ;全部入棧
    lea eax,g_szchangeAddStr 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
;----------------------------------------------------------------
;因爲修改信息的第一步也是先要將當前輸入的信息在已保存的數組中查詢
;1.輸入數據   g_strTemContacts CONTACTSSTRUCT <'0','0'> ;接收輸入信息
    lea edi,[g_strTemContacts.szName];保存結構體中名字的地址
    push edi
    ;g_szScanName BYTE '%s',0
    push offset g_szchangeAdd 
    call crt_scanf
    add esp,8
;2.開始查詢
    mov ecx,0 ;初始化循環次數(默認從0開始循環)
CYCLE_MARK:   ;標號
    cmp ecx,g_nCount
    ;如果相等就說明查找完畢沒找到
     je allennot     ;ret
;2.1根據ecx 的值找到下一個結構體名字數組的地址
    lea esi,[g_stContacts] ;保存數據的結構體數組
    lea edi,[g_strTemContacts.szName];剛輸入的名字
    mov eax,sizeof(CONTACTSSTRUCT) ;計算大小
    imul eax,ecx
    add esi,eax
;2.2比較字符串
    mov eax,ecx ;保存循環次數
    mov ecx,6 ;初始化串操作循環次數(4字節比較)
    repe cmpsd dword ptr [esi],dword ptr [edi] ;查看repe系列指令的使用原理
    je CARRIEDOUT_MAKR  ;如果找到則跳轉(轉出信息)
    mov ecx,eax         ;如果沒有  還原ecx
    inc ecx             ;循環次數加1
    jmp CYCLE_MARK      ;無條件跳轉到外層循環開始位置
CARRIEDOUT_MAKR:
;----------------------------------------------------------------
    pushad ;全部入棧
    lea eax,g_szchange   
    push eax
    call crt_printf     ;g_szchange BYTE '請輸入用戶名密碼格式如:allen 123',0ah,0dh,0
    add esp,4
    popad ;全部出棧 
;----------------------------------------------------------------   
    ;修改信息
    mov ecx,eax
    lea esi,[g_stContacts]
    mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小 
    imul ebx,ecx
    add esi,ebx
    lea edx,[esi+CONTACTSSTRUCT.szName] ;用戶名
    lea eax,[esi+CONTACTSSTRUCT.szPhNumber] ;電話號碼
    push eax
    push edx
    push offset g_szScanfFormat ;g_szScanfFormat BYTE '%s %s',0
    call crt_scanf
    add esp,12    ;add esp,8
    jmp allenretn
;----------------------------------------------------------------
allennot:           ;沒有
    lea eax,g_szchangernot 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
    popad ;全部出棧 
    ret
allenretn:           ;成功
    lea eax,g_szchangeretur 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
    popad ;全部出棧 
    ret
ModifyData endp
;刪除用戶信息
RemoveData proc
    pushad ;全部入棧
    lea eax,g_szremoveAddStr 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
;----------------------------------------------------------------
;1.輸入數據
    lea edi,[g_strTemContacts.szName];保存要刪除的用戶名
    push edi
    ;g_szScanName BYTE '%s',0
    push offset g_szScanName 
    call crt_scanf
    add esp,8
;2.開始查詢
    mov ecx,0 ;初始化循環次數(默認從0開始循環)
CYCLE_MARK:   ;標號
    cmp ecx,g_nCount
    ;如果相等就說明查找完畢
     je allennot     ;ret
;2.1根據ecx 的值找到下一個結構體名字數組的地址
    lea esi,[g_stContacts] ;保存數據的結構體數組
    lea edi,[g_strTemContacts.szName];剛接收的用戶名
    mov eax,sizeof(CONTACTSSTRUCT) ;計算大小
    imul eax,ecx
    add esi,eax
;2.2比較字符串
    mov eax,ecx ;保存循環次數
    mov ecx,6 ;初始化串操作循環次數(4字節比較)
    repe cmpsd dword ptr [esi],dword ptr [edi] ;查看repe系列指令的使用原理
    je CARRIEDOUT_MAKR  ;如果找到則跳轉(轉出信息)
    mov ecx,eax         ;如果沒有  還原ecx
    inc ecx             ;循環次數加1
    jmp CYCLE_MARK      ;無條件跳轉到外層循環開始位置
CARRIEDOUT_MAKR:
;刪除
;將esi設置爲當前要刪除的結構體數組的首地址
    mov ecx,eax ;eax 是在上面獲取到的表示當前找到的數據的位置
    lea edi,[g_stContacts]
    mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小
    imul ebx,ecx
    add edi,ebx ;edi此時保存的是當前要刪除的結構體數組的首地址
    mov esi,edi ;esi此時也是當前要刪除的結構 體數組的首地址
    mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小
    add esi,ebx ;esi此時也是當前要刪除的結構體數組的下一個首地址
    add ecx,1   ;因爲保存數據時是從數組0開始的,所以加1用於計算需要
            ;移動多少個元素,和數據結構中的線性表一樣,蹭某個元素
            ;被刪除了後面的元素向前移動
    mov eax,g_nCount
    sub eax,ecx ;需要移動的次數
    mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小
    imul ebx,ecx 
    mov ecx,ebx   ;計算需要移動的字節
    rep movs BYTE ptr[edi],BYTE ptr[esi] ;開始移動(以一個字節的大小的移動)
                         ;移動完成後刪除最後一個結構體中的信息
    mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小
    push ebx ;大小
    push 0   ;內容
    push edi ;刪除的首地址
    call crt_memset ;調用置初始化函數
    add esp,12
    dec g_nCount
    push offset g_szOK  ;操作成功
    call crt_printf  
    add esp,4
    push 20
    call Sleep  
    ;add esp,4
    jmp allenretn         
;----------------------------------------------------------------
allennot:           ;沒有
    lea eax,g_szremovenot 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
    popad ;全部出棧 
    ret
allenretn:
    lea eax,g_szremoveretur 
    push eax
    call crt_printf     ;調用格式 crt_xxx
    add esp,4
    popad ;全部出棧 
    ret

RemoveData endp

;main
start:  
    ;元素個數
    ;g_nCount DWORD 0
    ;g_szCount BYTE '%d',0ah,0dh,0 
    ;輸出當前總個數
    push g_nCount
    push offset g_szCount
    call crt_printf     
    add esp,8
    ;g_start5 BYTE '請輸入選項查:',0
        push offset g_start5
        push offset g_start7
    push offset g_start4
    push offset g_start3
    push offset g_start2
    push offset g_start1
    push offset g_szstartFormat
    call crt_printf     ;調用格式 crt_xxx
    add esp,24

allen:
    ;scanf() 接收一個整數保存到g_num
    mov g_num,0;清0
    push offset g_num
    ;push eax   不能這樣必須是一個地址
    ;g_szstart7Format BYTE '%d',0
    push offset g_szstart7Format 
    call crt_scanf
    add esp,8   
    cmp eax,1   ;與crt_scanf的返回值比較就是接收的本來是數字就返回成功1 如果你打的不是字母就返回0
    jnz @T1
    ;mov g_num,eax
    ;mov eax,g_num
    ;if ==1
    cmp g_num,1
    je  myadd
    ;if==2
    cmp g_num,2
    je myremove
    ;if==3
    cmp g_num,3
    je mychange
    ;if===4
    cmp g_num,4
    je mycheck
    ;if===5
    cmp g_num,5
    je mycheckall
    ;else continue
    push offset g_start6
    push offset g_szstart6Format
    call crt_printf     ;調用格式 crt_xxx
    add esp,8
    jmp start
;增
myadd:  
    call ADD_USER
        jmp start
;刪
myremove:
    call RemoveData
    jmp start
;改
mychange:
    call ModifyData
    jmp start
;查
mycheck:
    call FindData
        jmp start
;查all
mycheckall:
    call FindDataAll
        jmp start

@T1:
        call crt_getchar ;用這個把字母緩衝掉
        cmp eax,0ah      ;一直比對到最後0ah表示換行或回車
        jnz @T1
        push offset g_start6
    push offset g_szstart6Format
    call crt_printf     ;調用格式 crt_xxx
    add esp,8
        jmp start
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        invoke crt__exit, 0    
end start
end

有個 bug 要清緩衝(清緩衝的代碼在最上面的註釋裏)就是你所有接收都用的一個結構體所以導致有緩衝 清緩衝思路是你用完那個結構體在後面把他清爲 0
win 32彙編 中有個非常嚴重的問題是你調用 scanf 接收的是%d如果你輸入字符串 會死循環下次不會再調 scanf (原因有緩衝)解決方案見代碼

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