ASM16

通讯录

处理菜单选项

1
2
3
4
5
6
7
8
9
10
11
cmp al,'1'
jz ADD1
cmp al,'2'
jz DELETE1
cmp al,'3'
jz MODIFY1
cmp al,'4'
jz QUERY1
cmp al,'5'
jz EXIT1
jmp DEFAULT1

根据用户输入的选项跳转到对应的处理代码段。如果输入无效,跳转到DEFAULT1处理。

添加联系人

1
2
3
mov dx, offset NEXT_LINE
mov ah, 09h
int 21h

然后换行

1
2
3
4
ADD1:   ;增加联系人
mov dx,offset INPUT_NAME
mov ah,09h
int 21h

提示输入联系人姓名。

09h - 显示字符串

功能描述:显示从DX寄存器指向的内存地址开始的字符串,直到遇到字符串结束符号$为止。

输入

  • DX:指向要显示的字符串的地址
  • AH:09h

输出:将字符串显示在屏幕上

1
2
3
mov dx,offset NAME_BUF
mov ah,0Ah
int 21h

读取用户输入的姓名,存储在NAME_BUF中。

0Ah - 输入字符串

功能描述:从标准输入设备(通常是键盘)读取字符串并存储到由DX指向的缓冲区中。用户输入的字符串存储在缓冲区中,以回车键(Enter)结束。

输入

  • DX:指向输入缓冲区的地址
  • AH:0Ah

输出:输入的字符串存储在缓冲区中,第一个字节表示缓冲区的大小,第二个字节表示实际输入的字符数,后续字节存储实际输入的字符。

1
2
3
4
5
mov bx, dx                  ; 将 DX 寄存器的值(缓冲区地址)移动到 BX 寄存器中
mov al, byte ptr [bx+1] ; 从 [BX + 1] 地址处读取实际输入的字符数,存储到 AL 寄存器中
mov ah, 0 ; 将 AH 寄存器置为 0
mov si, ax ; 将 AX 寄存器的值移动到 SI 寄存器中
mov byte ptr [bx+si+2], '$' ; 在输入字符串末尾添加 '$' 字符

将姓名字符串的结尾设为$,以便显示。

  1. mov bx, dx
    
    1
    2
    3
    4
    5

    - 将 `DX` 寄存器的值移动到 `BX` 寄存器。此时,`BX` 寄存器中存储的是输入缓冲区的地址。

    2. ```
    mov al, byte ptr [bx+1]
    - `BX` 寄存器指向输入缓冲区。 - 输入缓冲区的结构是: - 第一个字节:缓冲区的最大长度 - 第二个字节:实际输入的字符数 - 后续字节:存储实际输入的字符 - `[bx+1]` 是实际输入的字符数的地址。将该值即实际输入的字符数移动到 `al` 寄存器中。
  2. mov byte ptr [bx+si+2], '$'
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    - `SI` 寄存器中存储的是实际输入的字符数。
    - `[bx+si+2]` 是输入字符串末尾的下一个位置。
    - 将 `$` 字符存储到 `[bx+si+2]` 位置,标志输入字符串的结束。

    **示例**

    假设缓冲区 `NAME_BUF` 定义如下:

    NAME_BUF db 20, 0, 20 dup(0)
    1
    2
    3

    输入 `"John"` 后,缓冲区的内容如下:

    20, 4, 'J', 'o', 'h', 'n'
    1
    2
    3
    4
    5
    6
    7

    执行这段代码后:

    1. `BX` 指向缓冲区起始地址。
    2. 从 `[bx+1]` 读取实际输入的字符数 `4`,存储到 `SI`。
    3. 在 `[bx+4+2]` 即 `[bx+6]` 位置写入 `$`,缓冲区变为:

    20, 4, 'J', 'o', 'h', 'n', '$'
    1
    2
    3

    这使得输入的字符串以 `$` 结束,可以使用 DOS 中断 21h, 功能码 09h 显示字符串。

    mov dx,offset INPUT_PHONE mov ah,09h int 21h
    1
    2
    3

    提示输入电话号码。

    mov dx,offset PHONE_BUF mov ah,0Ah int 21h
    1
    2
    3

    读取用户输入的电话号码,存储在`PHONE_BUF`中。

    mov bx,dx mov al,byte ptr [bx+1] mov ah,0 mov si,ax mov byte ptr [bx+si+2],'$'
    1
    2
    3

    将电话号码字符串的结尾设为`$`,以便显示。

    ;保存数据 mov bx,offset ALL_DATA mov ax,ds:[DATA_COUNT] mov cx,34 mul cx add bx,ax ;ary+count*34
    1
    2
    3

    计算新联系人在`ALL_DATA`中的存储位置。

    ;给标志 mov word ptr [bx],1 mov cx,8 mov si,2 mov bp,offset NAME_BUF LOOP1: mov ax,word ptr ds:[bp+si] mov word ptr [bx+si],ax add si,2 dec cx jnz LOOP1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    复制姓名数据到`ALL_DATA`中的对应位置。

    **`mov ax, word ptr ds:[bp+si]`**:

    - 从 `NAME_BUF`(`BP` 寄存器指向)加上 `SI` 偏移量的位置读取一个字(16 位)到 `AX` 寄存器。

    **`mov word ptr [bx+si], ax`**:

    - 将 `AX` 中的数据写入到 `BX` 指向的位置加上 `SI` 偏移量的位置。

    **`add si, 2`**:

    - 更新 `SI` 寄存器,将其偏移量增加 2,移动到下一个字(16 位)的位置。

    **`dec cx`**:

    - 将 `CX` 寄存器的值减 1,减少循环次数。

    **`jnz LOOP1`**:

    - 如果 `CX` 不为零,则跳回 `LOOP1` 标签,继续循环

    **示例**

    假设 `NAME_BUF` 的内容如下:

    NAME_BUF db 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120
    1
    2
    3

    执行这段代码时,`NAME_BUF` 从偏移量 `2` 开始的数据(`30 40`, `50 60`, `70 80`)将被复制到 `BX` 指向的内存位置,每次复制一个字(16 位)。这段代码假设 `NAME_BUF` 至少有 16 字节的数据。

    mov cx,8 mov si,18 mov di,2 mov bp,offset PHONE_BUF LOOP2: mov ax, word ptr ds:[bp+di] mov word ptr [bx+si], ax add si, 2 add di, 2 dec cx jnz LOOP2 inc ds:[DATA_COUNT]
    1
    2
    3

    复制电话号码数据到`ALL_DATA`中的对应位置,并增加联系人数量。

    jmp SHOW_MENU
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    返回显示菜单。

    ![image-20240914211913891](../image/image-20240914211913891.png)







    MyStack segment stack db 256 dup(?) MyStack ends

MyData segment
MENU1 db “1.add”, 0dh, 0ah
db “2.delete”, 0dh, 0ah
db “3.modify”, 0dh, 0ah
db “4.query”, 0dh, 0ah
db “5.exit”, 0dh, 0ah, ‘$’
INPUT_ERROR db “input error”, 0dh, 0ah, ‘$’
INPUT_NAME db “input name:”, 0dh, 0ah, ‘$’
INPUT_PHONE db “input phone:”,0dh, 0ah, ‘$’
NAME_BUF db 16, 0, 16 dup(0)
PHONE_BUF db 16, 0, 16 dup(0)
ALL_DATA db 340 dup(0) ;flag[2] name[16] phone [16]
NEXT_LINE db 0DH, 0AH, ‘$’
DATA_COUNT dw 0 ;数量
MyData ends

;代码段
MyCode segment
MAIN:
mov ax, MyData
mov ds, ax
mov es, ax ;定义数据段

SHOW_MENU:
mov dx, offset MENU1
mov ah, 09h
int 21h ;显示菜单

GET_INPUT:
mov ah, 01h ;获取用户输入
int 21h

cmp al, '1'
jz ADD1
cmp al, '2'
jz DELETE1
cmp al, '3'
jz MODIFY1
cmp al, '4'
jz QUERY1
cmp al, '5'
jz EXIT1
jmp DEFAULT1

ADD1:
mov dx, offset NEXT_LINE
mov ah, 09h
int 21h

;增加联系人
mov dx, offset INPUT_NAME
mov ah, 09h
int 21h

mov dx, offset NAME_BUF
mov ah, 0Ah
int 21h

; 获取输入的字符串长度并添加终止符
mov bx, dx
mov al, byte ptr [bx+1]
mov ah, 0
mov si, ax
mov byte ptr [bx+si+2], '$'

mov dx, offset NEXT_LINE
mov ah, 09h
int 21h

mov dx, offset INPUT_PHONE
mov ah, 09h
int 21h

mov dx, offset PHONE_BUF
mov ah, 0Ah
int 21h

; 获取输入的字符串长度并添加终止符
mov bx, dx
mov al, byte ptr [bx+1]
mov ah, 0
mov si, ax
mov byte ptr [bx+si+2], '$'

mov dx, offset NEXT_LINE
mov ah, 09h
int 21h

; 保存数据
mov bx, offset ALL_DATA
mov ax, ds:[DATA_COUNT]
mov cx, 34
mul cx
add bx, ax ; ary+count*34

; 给标志
mov word ptr [bx], 1
mov cx, 8
mov si, 2
mov bp, offset NAME_BUF

LOOP1:
mov ax, word ptr ds:[bp+si]
mov word ptr [bx+si], ax
add si, 2
dec cx
jnz LOOP1

mov cx, 8
mov si, 18
mov di, 2
mov bp, offset PHONE_BUF

LOOP2:
mov ax, word ptr ds:[bp+di]
mov word ptr [bx+si], ax
add si, 2
add di, 2
dec cx
jnz LOOP2

inc ds:[DATA_COUNT]
jmp SHOW_MENU

DELETE1:
jmp SHOW_MENU

MODIFY1:
jmp SHOW_MENU

QUERY1:
mov dx, offset NEXT_LINE
mov ah, 09h
int 21h

mov bx, offset ALL_DATA
mov cx, ds:[DATA_COUNT]

LOOP3:
cmp word ptr [bx], 0
je LABEL1

lea dx, [bx+2]
mov ah, 09h
int 21h
mov dx, offset NEXT_LINE
mov ah, 09h
int 21h

lea dx, [bx+18]
mov ah, 09h
int 21h
mov dx, offset NEXT_LINE
mov ah, 09h
int 21h

LABEL1:
add bx, 34 ; ary+count*34
dec cx
jnz LOOP3

jmp SHOW_MENU

EXIT1:
mov ax, 4c00h ;退出程序
int 21h

DEFAULT1:
mov dx, offset INPUT_ERROR
mov ah, 09h
int 21h
jmp SHOW_MENU

MyCode ends

end MAIN

1
2
3
4
5



### 查询联系人

QUERY1:
mov bx,offset ALL_DATA
mov cx,ds:[DATA_COUNT]
LOOP3:
cmp word ptr [bx],0
je LABEL1

1
2
3

开始查询联系人,从`ALL_DATA`中遍历联系人。

lea dx,[bx+2]
mov ah,09h
int 21h

mov dx,offset NEXT_LINE
mov ah,09h
int 21h

lea dx,[bx+18]
mov ah,09h
int 21h

mov dx,offset NEXT_LINE
mov ah,09h
int 21h

1
2
3

显示联系人姓名和电话号码。

LABEL1:
add bx,34 ;ary+count*34
dec cx
jnz LOOP3

1
2
3

处理下一个联系人。

jmp SHOW_MENU

1
2
3
4
5

返回显示菜单。

### 退出程序

EXIT1:
mov ax,4c00h
int 21h

1
2
3
4
5

退出程序。

### 默认处理无效输入

DEFAULT1:
mov dx,offset INPUT_ERROR
mov ah,09h
int 21h
jmp SHOW_MENU

1
2
3
4
5

显示输入错误信息,并返回显示菜单。

### 代码段结束

MyCode ends

end MAIN


结束代码段,并定义程序入口点为`MAIN`。