基本控制结构
字符与字符串的输入/输出方法 
DOS系统调用INT 21H提供了字符及字符串的I/O功能,例如:
     01H:从键盘读入一个字符
     02H:显示一个字符
     09H:显示一个字符串
     0AH:从键盘读入一个字符串
1. 从键盘读入一个字符
    功能号:01H
    出口参数:AL = 输入字符的ASCII码
    功能:等待从键盘读入一个字符,将其ASCII码送入AL,同时将该字符显示在屏幕上。
    调用方法:
 mov ah, 1
 int 21h  
    说明:输入一个字符后,不需要回车。若只键入回车,则AL = 0DH。
2. 显示一个字符
     功能号:02H
     入口参数:DL = 要显示字符的ASCII码
    功能:在当前光标位置显示DL中的字符,光标右移。
     调用方法示例:
 mov dl, 'A' ; 显示字符'A'
 mov ah, 2
 int 21h  
      说明:显示字符0DH和0AH将产生回车和换行的作用。
3. 显示一个字符串
    功能号:09H
    入口参数:DS:DX = 欲显示字符串在内存的首地址,且字符串必须以'$'(24H)作为结束符。
    功能:在当前光标位置,显示由DS:DX所指的、以'$'结尾的字符串,且光标右移。其中,'$'不算在显示的字符串之内。
    调用方法示例:
 String db 'Hello!', '$'  ; 显示字符串'Hello!'
  mov ax, seg String  
  mov ds, ax  
  mov dx, offset String
  mov ah, 9
  int 21h  
   4. 从键盘读入一个字符串
    功能号:0AH
    入口参数:DS:DX = 输入缓冲区首地址
    输入缓冲区格式:第0字节事先设置为缓冲区最多能容纳的字符个数(包括回车);第1字节将存放实际字符个数(不包括回车),由系统自动设置;从第2字节开始存放实际输入的字符串,最后为回车符。
    功能:从键盘读入一个字符串,存入DS:DX所指的缓冲区。
    调用方法示例:
 buf db 10, ?, 10 dup (?)  ; 定义输入缓冲区
  mov ax, seg buf  
  mov ds, ax  
  lea dx, buf
  mov ah, 0ah
  int 21h  
5. 字符与字符串的输入/输出举例
 DOS系统调用只提供了字符与字符串的输入/输出方法。如果要输入/输出其它类型的数据,如常用的整数,则必须由应用程序来实现与字符之间的转换。例如,欲输出整数126,只能以字符(串)的方式输出'1' 、 '2' 、 '6' 。
 对于程序员来说,在需要用户输入时给出输入提示,对输入数据进行有效性检查,在输出结果时说明其表示的含义,是一种好的设计习惯。
 
JMP指令的灵活运用 
 用JMP指令实现转移的多种方法:
 使用标号, 近转移
 使用标号, 远转移
 以通用寄存器表示目标偏移地址
 以内存变量表示目标偏移地址
 以内存变量表示目标的32位分段地址
双分支结构  
       双分支结构相当于高级语言的IF-THEN-ELSE形式。IF-THEN结构只是IF-THEN-ELSE形式的特例,即ELSE部分为空。
      通常,使用条件转移指令Jcc与无条件转移指令JMP来实现分支。一般必须先安排比较或算术、逻辑运算等影响标志位的指令,然后用Jcc指令判断条件,以实现分支转移。
      对应于IF-THEN-ELSE结构的80x86汇编语言代码形如:
 <为测试条件cc做准备>
         Jcc    ElseCode
         <THEN 程序段>
       jmp     EndOfIF
ElseCode:
    <ELSE 程序段>
EndOfIF:
       注意,程序隐含是顺序执行的,在THEN分支体执行后,不会自动跳过ELSE分支体,而是继续执行其后的代码。
对应于IF-THEN结构的80x86汇编语言代码形如:
 <为测试条件cc做准备>
         Jcc  EndOfIF
         <THEN 程序段>
EndOfIF:

多分支结构  
    多分支结构相当于高级语言的CASE语句。
    多分支程序的设计方法主要有:
 逻辑分解方法
将多分支结构以逻辑等效的方法,分解为一串双分支结构。
 地址表方法
   在数据段定义一个地址表,依次存放各分支对应处理程序的入口地址。
   通过将相应处理程序入口地址取入某寄存器,用间接转移指令实现转移。
 转移表方法
   在代码段建立一个转移表,依次存放实现各分支的转移指令。
   通过跳到转移表的相应位置执行其中的转移指令,从而实现转到相应分支的处理程序。

循环结构
 
循环结构的基本形式 
循环结构的两种基本形式:
 WHILE结构:先判断、后执行
     其特点是进入循环后,先判断循环控制条件。若满足循环结束条件,则退出循环;否则,继续执行循环体。循环体可能一次也不执行。
 UNTIL结构:先执行、后判断
     其特点是进入循环后,先执行循环体,然后判断循环控制条件。若满足循环结束条件,则退出循环;否则,继续执行循环体。循环体至少执行一次。该结构相当于PASCAL语言的REPEAT-UNTIL结构或C语言的DO-WHILE结构。
     具体选择哪一种结构,取决于问题的特性以及使用者的偏好。一般来说,WHILE结构可能用得多一些。
      此外,象高级语言的FOR循环结构,主要用在循环次数已知的情况下。FOR结构总可以转换为等价的WHILE或UNTIL结构。
循环程序的控制方法  
(1)计数控制
        适用于循环次数已知的情况,包括正计数与倒计数两种方法。 
(2)条件控制
        在实际问题中,常常有循环次数未知的情况。此时,就必须通过特定条件来控制循环。
(3)开关控制
        有时,循环内部又有分支,且每次循环执行的分支具有一定规律,这种结构非常类似于多分支结构。此时,可以采用开关来控制循环。具体方法是:
       在进入循环前,预置第一次循环的开关走向;在每次循环结束前,设置下一个开关方向,以便执行相应的操作。
      在实际应用中,开关的形式多种多样。例如,设置一个状态变量,取值0、1和2,分别表示执行的不同操作,就是一个开关。
(4)逻辑尺控制
       如果循环内分支的规律性不强,开关控制方法就难以胜任了。一种较有效的方法就是逻辑尺控制。所谓逻辑尺,就是一个位串,用1位或多位来控制每次循环所执行的操作。
 
串操作
串操作指令及其用途
1.  串操作指令
(1) MOVS(Move String):串传送
       语法格式:
 MOVSB
 MOVSW
 MOVSD
      功能描述:
 ES:[DI] = DS:[SI];
         if ( DF = 0 ) then
               SI = SI + size;     DI = DI + size;
       else
               SI = SI – size;      DI = DI – size;
        endif
      其中,size = 1(B)、2(W)或4(D)。
      也就是说,MOVS(B/W/D)将DS:SI所指源串的1个元素(字节/字/双字)复制到ES:DI所指的内存单元。然后,SI和DI增加或减少1/2/4。若DF = 0,则增加,否则减少。
      对标志位的影响:无。
(2)LODS(Load String):串装入
      语法格式:
 LODSB
 LODSW
 LODSD
      功能描述:
 AL/AX/EAX = DS:[SI];
         if ( DF = 0 )then
              SI = SI + size;
       else
              SI = SI – size;
        endif
      其中, size = 1(B)、2(W)或4(D)。
      也就是说,LODS(B/W/D)将DS:SI所指源串的1个元素(字节/字/双字)复制到AL/AX/EAX。然后,SI增加或减少1/2/4。若DF = 0,则增加,否则减少。
      对标志位的影响:无。
 
(3)STOS(Store String):串存储
      语法格式:
 STOSB
 STOSW
 STOSD
      功能描述:
 ES:[DI] = AL/AX/EAX;
         if ( DF = 0 )then
                   DI = DI + size;
       else
                        DI = DI – size;
        endif
      其中,size = 1(B)、2(W)或4(D)。
      也就是说,STOS(B/W/D)将AL/AX/EAX的值复制到ES:DI所指的内存单元。然后,DI增加或减少1/2/4。若DF = 0,则增加,否则减少。
      对标志位的影响:无。
(4)CMPS(Compare Strings):串比较
      语法格式:
 CMPSB
 CMPSW
 CMPSD
      功能描述:
 DS:[SI] – ES:[DI];
         if ( DF = 0 )then
               SI = SI + size;  DI = DI + size;
       else
               SI = SI – size;  DI = DI – size;
        endif
      其中,size = 1(B)、2(W)或4(D)。
      也就是说,CMPS(B/W/D)将DS:SI所指源串的1个元素(字节/字/双字)与ES:DI所指目的串的1个元素(字节/字/双字)进行比较,根据比较结果设置标志位。然后,SI和DI增加或减少1/2/4。若DF = 0,则增加,否则减少。
      对标志位的影响:同CMP。
(5)SCAS(Scan String):串扫描
      语法格式:
 SCASB
 SCASW
 SCASD
      功能描述:
 AL/AX/EAX – ES:[DI];
         if ( DF = 0 )then
                   DI = DI + size;
       else
                   DI = DI – size;
        endif
      其中,size = 1(B)、2(W)或4(D)。
       也就是说,SCAS(B/W/D)将AL/AX/EAX与ES:DI所指目的串的1个字节/字/双字进行比较,根据比较结果设置标志位。然后,DI增加或减少1/2/4。若DF = 0,则增加,否则减少。
 
(6)重复前缀
 REP  ; 当CX <> 0时,重复执行后面的串指令
   ; 每执行1次,CX = CX – 1
   ; 只能用在MOVS、LODS或STOS(B/W/D)之前
 REPZ/REPE ; 当CX <> 0且ZF = 1时,重复执行后面的串指令
   ; 每执行1次,CX = CX – 1
   ; 只能用在CMPS(B/W/D)或SCAS(B/W/D)之前
 REPNZ/REPNE ; 当CX <> 0且ZF = 0时,重复执行后面的串指令
   ; 每执行1次,CX = CX – 1
   ; 只能用在CMPS(B/W/D)或SCAS(B/W/D)之前
      说明:
           若CX初值为0,则不执行任何操作,而且标志位不变。
 
2. 串指令的共性
 源串:地址由DS:SI表示。
 目的串:地址由ES:DI表示。
 自动修改地址:每次数据操作后,SI和DI自动递增或递减,取决于操作的数据类型(字节、字或双字)以及DF的值。若DF = 0, 则SI和DI自动增加1、2或4。否则,减1、2或4。可以使用CLD或STD指令设置DF。
 计数器:使用重复前缀时,由CX表示数据个数,每重复1次操作,CX减1。
3. 串指令的用途
      串指令主要用于处理连续的内存单元,与重复前缀配合使用更有效。例如:
      MOVS用于将一个内存块的数据复制到另一块;
      CMPS用于比较两个内存区的数据;
      SCAS可以在一个内存区中扫描与给定值首次匹配或不匹配的元素;
      STOS能将一个内存区的所有单元初始化为给定值。
      LODS一般不用重复前缀。
 
字符串处理
1. ASCII字符串的表示方法
     字符串是一种特殊的数据串,比其它类型的串更常使用,因此,有时将字符串简称为串。
     ASCII字符串的表示方法主要有下列两种:
     (1)长度前缀法。
由首字节指出字符串长度,常被称作Pascal串,为Pascal语言的大多数版本所支持。例如:
 String1 db    6, 'String‘
(2)0终止法。
以0作为结束标志,常被称作C串,为C/C++语言所采用。例如:
 String2 db    ' String ', 0
2. 字符串处理举例