汇编语言习题:键盘输入一个包含若干个‘*‘的字符串,试编写子程序分别将字符串前端、中间、最后面的‘*‘及其所有‘*‘去除。

文章详细介绍了汇编语言中如何编写子程序,包括过程定义、NEAR/FAR属性的区别,以及如何处理字符串,如去除前后星号、小写字母转大写等。同时展示了如何调用子程序实现功能,如统计星号数量、字符转换和菜单选择操作。
摘要由CSDN通过智能技术生成

题目:键盘输入一个包含若干个星号的字符串,试编写子程序分别将字符串前端、中间、最后面的星号及其所有星号去除。

详解:

本文是目前本专栏最难的一篇,需要的知识功底很多,如果在一些语法学习不够扎实,请移步往期文章:
汇编语言(Assembly Language)习题:键盘输入一个字符串,试将其中的小写字母转换为大写字母,其它字符保持不变。
汇编语言(Assembly Language)习题:键盘输入任意一个字母,显示其前导字母、字母自身、后续字符共三个字母。

汇编语言习题:编写程序,将一个包含有20个有符号数据的数组ARRAYM分成两个数组:正数数组ARRAYP和负数数组ARRAYN。设数据均为8位。试分别统计负数个数,并计算正数之和。
汇编语言习题:键盘输入2个两位十进制数(可以是负数),并输入加、减、乘、除四个运算符中的某一个,完成对应运算,并输出相应的结果。若输入的第二个数为0,就退出计算。
在此着重讲解一下子程序,在前几期文章有用到过,相信各位已经基本了解了用法,在此系统介绍:

  • 在程序设计中,我们会发现一些多次无规律重复的程序段或语句序列。解决此类问题一个行之有效的方法就是将它们设计成可供反复调用的独立的子程序结构,以便在需要时调用。在汇编语言中,子程序又称过程

  • 子程序可以实现源程序的模块化,可以简化源程序结构,可以提高编程效率

  • 调用子程序的程序称为主调程序主程序

  • 子程序的定义是由过程定义伪指令PROC和ENDP来完成的。其格式如下:

   过程名  PROC [NEAR/FAR] 
             ┆
   过程名  ENDP
  • 其中PROC表示过程定义开始,ENDP表示过程定义结束。过程名是过程入口地址的符号表示。
  • 一般过程名同标号一样,具有三种属性,即段属性、偏移地址属性以及类型属性。
  • 取值有如下两种:
    (1)NEAR属性:调用程序和子程序在同一代码段中(段内调用)
    (2)FAR属性:调用程序和子程序不在同一代码段中(段间调用)
  • 对简化段定义格式,在微型、小型和紧凑存储模式下,过程的缺省属性为near;在中型、大型和巨型存储模式下,过程的缺省属性为far。对完整段定义格式,过程的缺省属性为near
  • 用户可以在过程定义时用nearfar改变缺省属性。

调用程序和子程序在同一代码段中

两种形式

code  segment
     
main  proc  far
          ......
          call subr1
          ......
          ret
main  endp

subr1  proc near
           ......
           ret
subr1  endp

code  ends
code  segment
     
main  proc  far
          ......
          call subr1
          ......
          ret

subr1  proc near
           ......
           ret
subr1  endp

main   endp
code   ends

调用程序和子程序不在同一代码段中

segx   segment
  subt   proc  far
         ......
        ret
  subt   endp
          ......
        call  subt
          ......
segx   ends

segy   segment
           ......
        call  subt
           ......
segy   ends

DATAS SEGMENT

DATAS SEGMENT
     msg1 db 'input a string:',0ah,0dh,'$'         ;输出的字符串,不难理解
     msg2 db 'result:',0ah,0dh,'$'
     msg3 db 0ah,0dh,'$'
     msg4 db '********************menu********************$'
     msg5 db '1.******************************************$'
     msg6 db '2.******************************************$'
     msg7 db '3.******************************************$'
     msg8 db '4.******************************************$'
     msg10 db '5.******************************************$'
     msg9 db 'input a number:',0ah,0dh,'$'
     msg11 db 'END',0ah,0dh,'$'
     buff db 50 ,?,50 dup(?) 
     
     count1 dw 0       ;统计前面*数量
     count2 dw 0       ;统计后面*数量
     
     
DATAS ENDS

CODES SEGMENT(1)

    mov dx,offset msg1    ;提示输入
    mov ah,9
    int 21h
    
    lea dx,buff          ;输入字符串
    mov ah,10
    int 21h
    
    lea si,buff+1        ;取第二个字节地址送给si
                           ;设置cx=字符串长度,实际输入的字符个数
    mov ch,0               
    mov cl,[si]

这段代码不难理解,已在往期文章讲解,在此不再赘述:
汇编语言(Assembly Language)习题:键盘输入一个字符串,试将其中的小写字母转换为大写字母,其它字符保持不变。

CODES SEGMENT(2)

    inc si                 ;从第一个字符开始计数
front: mov al,[si]
       cmp al,'*'        ;计数前面的*数量
       jz change1         ;思考一下为什么这两句不能换位置?  jz change1 jmp next1
       jmp next1
       
change1:add count1,1
        inc si 
        loop front     ;这段循环指令并没有用到cx=0结束循环,思考怎么退出循环的?
        
next1:                 ;当然是[si]!='*'的时候通过  jmp next1  指令过来了
             
         lea si,buff+1         ;设置cx=字符串长度,实际输入的字符个数
        mov ch,0
        mov cl,[si]
        
        add si,cx           ;同理,这里从字符串最后一个字符开始统计,所以要执行 add si,cx ,此时si指向字符串最后一个字符
back:  mov al,[si]
       cmp al,'*'        ;计数后面的*数量
       jz change2
       jmp next2
       
change2:inc count2
        dec si            ;相应地,si应该自减不是自增
        loop back        
          
next2: 
       mov bx,10

CODES SEGMENT(3)

next2: 
       mov bx,10        ;bx的作用见末尾
selections:
        
        call crlf      
       mov dx,offset msg9
       mov ah,9
       int 21h
       
       mov ah,1
       int 21h
       
       cmp al,31h                  ;比较输出的数字,即数字对应的ASCII码
       jz number_1
       
       cmp al,32h
       jz number_2
       cmp al,33h
       jz number_3
       cmp al,34h
       jz number_4
       cmp al,35h
       jz number_5
       
number_1:     call  number1
               jmp  next_
number_2:     call  number2
               jmp  next_
number_3:     call  number3
               jmp  next_
number_4:     call  number4
               jmp  next_
number_5:     call  number5
               jmp  over
  
  ;
next_: 
       dec bx        ;显然循环执行10次,通过bx=0的条件退出循环,至于问为什么用bx而不是别的寄存器,当然是为了防止数据更改,寄存器不够用了。
       jnz  selections
jmp over       

CODES SEGMENT(4)

输入数字1,2,3,4,5,分别完成不同的功能,见文末。以数字1为例:

number1 proc near         
     call crlf
     lea si,buff+2 
     mov cl,buff+1
     mov ch,0
     sub cx,count1       ;计数减去前面'*'的数量
     
      
     add si,count1      ;从前往后第一个非'*'字符开始
continue_1:mov dl,[si]
           mov ah,2
           int 21h      ;将DL寄存器中的字符送显示器显示
           
           inc si
           dec cl 
           jnz continue_1
      
       ret
number1 endp

完整代码

DATAS SEGMENT
     msg1 db 'input a string:',0ah,0dh,'$'
     msg2 db 'result:',0ah,0dh,'$'
     msg3 db 0ah,0dh,'$'
     msg4 db '********************menu********************$'
     msg5 db '1.******************************************$'
     msg6 db '2.******************************************$'
     msg7 db '3.******************************************$'
     msg8 db '4.******************************************$'
     msg10 db '5.******************************************$'
     msg9 db 'input a number:',0ah,0dh,'$'
     msg11 db 'END',0ah,0dh,'$'
     buff db 50 ,?,50 dup(?) 
     
     count1 dw 0       ;统计前面*数量
     count2 dw 0       ;统计后面*数量
     
     
DATAS ENDS

STACKS SEGMENT
   dw   128  dup(0)
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    
    call menu      ;打印目录
    
    mov dx,offset msg1    ;提示输入
    mov ah,9
    int 21h
    
    lea dx,buff          ;输入字符串
    mov ah,10
    int 21h
    
    lea si,buff+1        ;取第二个字节地址送给si
                           ;设置cx=字符串长度,实际输入的字符个数
    mov ch,0               
    mov cl,[si]
    
    inc si                 ;从第一个字符开始计数
front: mov al,[si]
       cmp al,'*'        ;计数前面的*数量
       jz change1
       jmp next1
       
change1:add count1,1
        inc si 
        loop front 
        
next1: 
             
         lea si,buff+1         ;设置cx=字符串长度,实际输入的字符个数
        mov ch,0
        mov cl,[si]
        
        add si,cx
back:  mov al,[si]
       cmp al,'*'        ;计数前面的*数量
       jz change2
       jmp next2
       
change2:inc count2
        dec si 
        loop back        
          
next2: 
       mov bx,10
selections:
        
        call crlf      
       mov dx,offset msg9
       mov ah,9
       int 21h
       
       mov ah,1
       int 21h
       
       cmp al,31h                  ;比较输出的数字
       jz number_1
       
       cmp al,32h
       jz number_2
       cmp al,33h
       jz number_3
       cmp al,34h
       jz number_4
       cmp al,35h
       jz number_5
       
number_1:     call  number1
               jmp  next_
number_2:     call  number2
               jmp  next_
number_3:     call  number3
               jmp  next_
number_4:     call  number4
               jmp  next_
number_5:     call  number5
               jmp  over     ;直接退出,结束程序
  
  ;
next_: 
       dec bx
       jnz  selections
jmp over       
       
crlf proc near
     mov dx,offset msg3
   mov ah,9
   int 21h  
    ret
crlf endp   

menu proc near    
   mov dx,offset msg4
   mov ah,9
   int 21h
   
   call crlf
   
   mov dx,offset msg5
   mov ah,9
   int 21h
   
   call crlf
   
   mov dx,offset msg6
   mov ah,9
   int 21h
   
   call crlf
   
   mov dx,offset msg7
   mov ah,9
   int 21h
   
   call crlf
   
   mov dx,offset msg8
   mov ah,9
   int 21h
   
   call crlf
   
   mov dx,offset msg10
   mov ah,9
   int 21h
   
   call crlf
   ret
menu endp


number1 proc near         
     call crlf
     lea si,buff+2 
     mov cl,buff+1
     mov ch,0
     sub cx,count1
     
      
     add si,count1
continue_1:mov dl,[si]
           mov ah,2
           int 21h
           
           inc si
           dec cl 
           jnz continue_1
      
       ret
number1 endp

number3 proc near        
    call crlf
     lea si,buff+2 
     mov cl,buff+1
     mov ch,0
     sub cx,count2
     
      
     
continue_3:mov dl,[si]
           mov ah,2
           int 21h
           
           inc si
           dec cl 
           jnz continue_3

    ret
number3 endp

number4 proc near          
     call crlf
     lea si,buff+2 
     mov cl,buff+1
     mov ch,0
    
      
     
continue_4:mov dl,[si]
           cmp dl,'*'
           jz later1
           mov ah,2
           int 21h
           
later1:   inc si
           dec cl 
           jnz continue_4
 
    ret
number4 endp

number2 proc near         
     call crlf
     
     mov cx,count1
input1:mov dl,'*'
       mov ah,2
       int 21h
       dec cx
       jnz input1
          
     lea si,buff+2 
     mov cl,buff+1
     mov ch,0
     sub cx,count1
     sub cx,count2
      
     add si,count1
continue_2:mov dl,[si]
           cmp  dl,'*'
           jz   later2
           mov ah,2
           int 21h
           
later2:    inc si
           dec cl 
           jnz continue_2
           
 mov cx,count2
input2:mov dl,'*'
       mov ah,2
       int 21h
       dec cx
       jnz input2



    ret
number2 endp

number5 proc near          ;5
    call crlf 
    mov dx,offset msg11    ;提示结束
    mov ah,9
    int 21h


    ret
number5 endp

over:   
    MOV AH,4CH
    INT 21H
CODES ENDS
    END START

运行结果

在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值