汇编语言中的字符串、代码转换.ppt
第5章 汇编语言程序中的字符串、代码转换与列表,开 始,5.1 汇编语言的字符串5.2 数据的分类和统计程序,返回本章目录,5.1 汇编语言的字符串,字符串及其操作指令5.1.2 字符串的运算,返回本节,1.字符串的定义及表示方法,现代计算机应用中,字符串在编辑加工,词法分析,符号处理等方面得到越来越广泛的应用。在设计具体的应用程序中,亦经常要使用各种字符串。因此,在非数值的数据处理过程中,字符及字符串的处理是一个重要的方面。一般地讲,字符串指一串字符,或者说,是字符的有限序列。如:6AN7BH,用ASCII码表示,并存储在连续的存储单元中,每个字符占一个字或一个字节。用比较专业的术语来说,字符串是一种特殊的线性表,它的数据元素仅由一个字符组成。一个字符串中包含的字符个数,称为这个字符串的长度。长度为零的字符串称为空串,它不包含任何字符。字符串通常用单引号或双引号括起来,例如:(1)”X1”(2)ABC,字符串及其操作指令,字符串所能包含的字符,依赖于具体机器的字符集。目前世界上应用最广的字符集是ASCII码字符集。存储字符串的方法也就是存储列表的一般方法。最简单最普遍的方法是顺序存储,还有链接存储等,这里仅讨论顺序存储的字符串。字符串的表示在80868088宏汇编语言中,可以借助数据定义语句DB(因一个ASCII码是7位)来定义,字符串的特征表示一般有两种,一种是在字符串的尾部用00H作标记,另一种是在字符串的前面空出一个单元,放置字符串的长度。例:STRI DB I am a student,0STR2 DB 4,ABCD,2.串操作指令,串操作指令完成对字符串的各种操作,操作是对一个一个字符(称为元素)而言的。因此,每一次操作都是针对一个字或一个字节进行的。其寻址方式多采用隐含寻址,源串元素固定使用SI,通常在现行的数据段,隐含段寄存器DS,但也允许段超越。目的串元素固定使用DI,隐含段寄存器ES,不允许段超越。在每次基本操作后,能够借助方向标志DF,自动修改地址指针。为下一次操作作准备。当DF0时,地址指针增量,即字节操作时,地址指针加1;字操作时,地址指针加2。当DF1时,地址指针减量,即字节操作时,地址指针减1;字操作时,地址指针减2。为此,8086处理器有两条方向标志指令:CLD(Clear Direction flag):置DF0;STD(Set Direction flag):置DF1;串操作是通过加重复前缀实现的,每次操作只对一个字或一个字符。为此,我们先讲重复前缀指令REP。,(1)重复前缀指令REP(或REPE、REPZ、REPNE、REPNZ)格式:REP strpri(strpri为串操作指令)功能:运用该指令,先要设置重复操作次数于CX之中。每执行一次,CX减1,直到CX=0时,只要(CX)0,就继续执行。说明:REPE、REPZ、REPNE、REPNZ分别表示如满足条件(上一步的结果:相等;为0;不相等;不为0),则继续执行。(2)MOVS串传送指令格式:可有三种MOVS DST,SRC;DST代表目的串元素,SRC代表源串元素MOVSB(字节);8位字符串操作,省略源串和目的串不写MOVSW(字);16位字符串操作,省略源串和目的串不写功能:该指令可以把由SI指向的数据段DS中的一个字(或字节)送到由DI指向的附加段ES中的一个字(或字节,目的串)中去,同时根据方向标志DF及数据格式(字或字节)对SI和DI进行修改。说明:1)如果是字节操作,则SI与DI变化时是1;如果是字操作,则SI与DI变化时是2。2)该指令不影响标志位。,(3)STOS存入串指令 格式:STOS DST;源串元素隐含在AL或AX,目的串元素由ES:DI指定STOSB(字节);8位字符串操作,省略源串和目的串不写STOSW(字);16位字符串操作,省略源串和目的串不写功能:该指令把AL或AX的内容(源串元素)存入由DI指定的附加段ES的某单元(目的串元素)中,并根据DF的值及数据类型修改DI的内容。说明:1)如果是字节操作则先将AL的内容存入DI指定的附加段的某单元DI中,然后DI再自加/减1;如果是字操作则将AX的内容存入DI指定的附加段的某单元DI,然后DI再自加/减2。2)该指令不影响标志位。,3LODS取串指令,格式:可有三种LODS SRC;源串元素由DS:SI指定的存储单元,目的串元素隐含在由DS:AL或DS:AX指定的存储单元LODSB;8位字符串操作,省略源串和目的串不写 LODSW;16位字符串操作,省略源串和目的串不写功能:该指令把由SI指定的数据段中某单元SI的内容送到AL或AX中,并根据方向标志及数据类型修改SI的内容。说明:1)如果是字节操作则先将由SI指定的单元内容送入AL中,然后SI再自加/减1;如果是字操作则将SI送入AX,然后SI再自加/减2。2)该指令不影响标志位。,5.SCAS串搜索指令,格式:可有三种SCAS DST;源串隐含在由DS:AL或DS:AX指定的存储单元,目的串隐含在由ES:DI指定的存储单元SCASB;8位字符串操作,省略源串和目的串不写SCASW;16位字符串操作,省略源串和目的串不写功能:该指令把AL(或AX)的内容与由DI指定的在附加段中的一个字节(或字)相减,但不保存结果,只根据结果置条件码。(CX)0,ZF=0,表示字符串未比较完,且已比较的字符元素不相同,尚未找到完全相同的字符串元素,还要继续比较。直到(CX)=0,ZF=1为止)。说明:1)每次操作后,自动修改SI和DI。如果是字操作,则SI和DI分别自动加/减1;如果是字操作,则SI和DI分别自动加/减2。2)该指令影响SF、ZF、AF、PF、CF和OF标志位。,4.CMPS串比较指令,格式:可有三种CMPS SRC,DST;源串元素在由DS:SI指定的存储单元,目的串元素在由ES:DI指定的存储单元CMPSB;8位字符串操作,省略源串和目的串不写CMPSW;16位字符串操作,省略源串和目的串不写功能:指令把由SI指向的数据段中的一个字(或字节)与由DI指向的附加段中的一个字(或字节)相减,但不保存结果,只根据结果置条件码(CX)0,ZF=1,表示字符串未比较完,且已比较的字符段完全相同,尚未找到不同之处,还要继续比较。直到(CX)=0,ZF=0为止)。说明:1)每次操作后,自动修改SI和DI。如果是字操作,则SI和DI分别自动加/减1;如果是字操作,则SI和DI分别自动加/减2。2)该指令影响SF、ZF、AF、PF、CF和OF标志位。,5.1.2 字符串运算,对字符串的基本运算有:(1)求字符串的串长(2)字符串的比较(3)字符串的连接(4)取子字符串(5)取子字符串序号除以上基本运算外,还有以下基本运算的组合运算:(1)插入(2)删除(3)查找并替换上述运算对字符串而言都是基本的,在引进字符串变量的高级语言中,一般都作为基本运算或基本内部函数来提供。下面举例说明字符串运算在汇编语言一级上的实现。,返回本节,例题:,1.求字符串的串长,【例5-1】内存STR单元中存放一字符串,结尾用00H作标记。编程求其串长并存入LEN单元。分析问题:由题意可知,只需按给定字符串的首地址,逐个与00H比较,若不是,则字符串长度计数器加1。若是,则将结果存于LEN单元。确定算法:采用比较循环指令,循环次数要数字符串的长度,这和本题的目标相同,编写程序就失去意义。故用逐个比较法,看字符其的ASCII码值是否大于00H,以此作为判定循环结束的控制条件。本题用JMP指令实现循环。,编写程序,可以想得到,需要MOV、LEA、CMP、JZ、INC和JMP等指令。最后要返回DOS。未想到的,在编写过程中随时添加,如XOR指令等。具体程序如下:DATA SEGMENTSTR DB I live in Anshan,00H;定义字符串STR,以00H结束LEN DB?;定义存放字符串长度的存储单元LENDATA ENDSCODE SEGMENT ASSUME CS:CSEG,DS:DSEGSTART:SLEN:MOV AX,DATA MOV DS,AX;数据段初始化LEA SI,STR;取字符串起始偏移地址送寄存器SI,定位XOR AL,AL;字符串长度计数器AL清0,画程序流程图:略。解题步骤如下:(1)取串首地址作指针;(2)设置计数器,供计算串长之用;(3)指针指向内容为00H?是,转6;(4)计数器加1,指针加1;(5)转3;(6)保存计数结果;(7)结束。确定汇编语言程序的基本框架:可见,该汇编语言程序的基本框架至少要两个段:数据段和代码段。数据段中至少定义2个变量:一个字符串变量STR,实际上是一个数组变量,每个字符的ASCII码为(71)位数,应选DB 类型。用寄存器SI定位。还有一个变量LEN,定义为存放字符串长度的存储单元,8位数已足够,选DB类型。其中间结果放在寄存器AL。,LOP:CMP BYTE PTRSI,00H;逐个比较字符串的每个字符,看其的ASCII值是否大于00H,以此判定串结束与否 JZ DONE;若不大于00H,而是等于,则转DONE语句INC AL;AL AL 1,计数器AL累加 INC SI;SI SI1,移到下一个字符JMP LOP;跳到LOP语句循环 DONE:MOV LEN,AL;保存结果MOV AH,4CHINT 21HCODE ENDSEND SLEN计算串长的程序也可以通过串搜索指令来实现,程序会更简洁,读者可自己试写出程序。,2.字符串的比较,【例5-2】编程比较内存中两个字符串:STR l和STR2,分别存放在不同单元,以00H作为结束标志。将比较结果存于FLAG单元。如果两串相等,FLAG为0;如果STR lSTR 2,则FLAG为1;如果STR 1 STR 2,则FLAG为FFH。分析问题:由题意可知,实际上试比较两个字符串的ASCII码值。方法:按给定字符串的首地址,将两个字符串的相应字符逐个比较,找出第一个不同字符。若未找到,则串相等;否则,根据不同字符的ASCII码,决定哪个串大。确定算法:采用比较循环指令,循环次数要数字符串的长度,这和本题的目标相同,编写程序就失去意义。故用逐个比较法,看字符其的ASCII码值是否大于00H,以此作为判定循环结束的控制条件。本题用JMP指令实现循环。,画程序流程图:略。解题步骤如下:(1)设置串首址指针1和指针2;(2)置FLAG单元为0;(3)串1或串2结束吗?是,转8;(4)指针1指向内容等于指针2指向内容?否,转7;(5)指针1和指针2;0IJl;(6)转(3);(7)若指针1指向内容指针2指向内容?则FLAG为1,否则为FFH;(8)结束。确定汇编语言程序的基本框架:可见,该汇编语言程序的基本框架至少要两个段:数据段和代码段。数据段中至少定义4个变量:两个字符串变量STR 1和STR 2,实际上是两个数组变量,每个字符的ASCII码为(71)位数,应选DB 类型。分别用寄存器SI和BX定位。还有两个变量FLAG 和LEN,分别定义为结果标志和存放字符串长度的存储单元,8位数已足够,选DB类型。其中间结果放在寄存器AH、AL,CH、CL。,编写程序,可以想得到,需要MOV、LEA、CMP、JZ、INC、DEC和JMP等指令。最后要返回DOS。未想到的,在编写过程中随时添加,如XOR指令等。具体程序如下:DATA SEGMENTSTR l DB I am a student,00HSTR2 DB I AM A STUDENT,00HFLAG DB?LEN DB?DATA ENDS CODE SEGMENTASSUME DS:DSEG,CS:CODE,START:MOV AX,DATAMOV DS,AX;数据段初始化LEA SI,STR 1;取串1起始偏移地址送寄存器SI,即设置串1首址指针1 LEA BX,STR2;取串2起始偏移地址送寄存器BX,即设置串2首址指针2 MOV FLAG,0;置FLAG单元为0MOV CL,0;寄存器CL清零 LOP:XOR AX,AX;寄存器AX清零CMP SI,AL;比较串1的第一个字符和0,是零吗?JZ DONE l;是零,转DONE lMOV AH,1;不是零,置未结束标志“1”DONE l:CMP BX,CL;比较串2的第一个字符和0,是零吗?JZ DONE2;是零,转DONE 2MOV AL,1;不是零,置未结束标志“1”,DONE2:OR AH,AL;将AH和AL作“或运算”JZ DONE;如果是零,串1和串2均结束,转DONE语句 MOV CH,SI;送串1的第一个字符到寄存器CHCMP CH,BX;比较串1的第一个字符和串2的第一个字符JNZ DONE3;二者不等,转DONE3语句INC SI;SI SI1,SI指向串1的下一个字符INC BX;BX BX1,SI指向串2的下一个字符JMP LOP;跳到LOP语句DONE3:JA DONE4;串1的码值 串2的码值,转DONE4语句DEC FLAG;否则,FLAGFFH,置小于标志“1”,即FFHJMP DONE;跳到DONE,结束DONE4:INC FLAG;FLAG01H,置大于标志DONE:MOV AH,4CHINT 21HCODE ENDSEND START本程序亦可以用串比较指令实现,请读者思考一下。然后看下例,【例5-3】设STRING 1是DS段中的一个50字节字符串,STRING 2是ES段中的一个50字节字符串,比较这两个字符串是否完全一样。若完全一样,置字节单元RESULT为0,否则,置字节单元RESULT为FFH。程序段如下:LEA SI,STRING 1;将源串首地址送SILEA DI,STRING 2;将目的串首地址送DIMOV CX,50;将寄存器CX作为计数器,送比较次数到CXCLD;使DF0,地址指针按增量方向修改REPZ CMPSB;比较两个字符串,重复操作CMPSB。如果相等,则继续比较下一个字节,SI和DI分别加1,CX减1JZ EQUAL;如果两个字符串相等,则转移到EQUAL语句MOV RESULT,0FFH;如果两个字符串不相等,则RESULT置0FFHJMP EXIT;转移至EXIT语句EQUAL:MOV RESULT,0;如果两个字符串相等,则将RESULT置0EXIT:HLT;停止,3.字符串的迁移,【例5-4】在数据段中有一个字符串,其长度为17,要求把它们传送到附加段中的一个缓冲区中。分析问题:题意很明白,将一个字符串,从数据段传送到附加段中。是一个反复传送操作。确定算法:采用重复送字符串操作,本题用REP MOVSB指令实现。画程序流程图:略。确定汇编语言程序的基本框架:可见,该汇编语言程序的基本框架至少要三个段:数据段、扩展段和代码段。数据段和扩展段中各定义1个字符串变量MESS 1和MESS 2,实际上是两个数组变量,每个字符的ASCII码为(71)位数,应选DB 类型。分别用寄存器SI和DI定位。设MESS l为源串,放在数据段中从符号地址MESS l开始的存储区内,每个字符占有一个字节;MESS 2为目的串,只能存放在附加段中从符号地址MESS 2开始空出17个字节的存储区内。程序则存放在代码段中。,编写程序,可以想得到,需要MOV、LEA、CLD和REP MOVSB等指令。最后要返回DOS。编制程序如下所示。DATA SEGMENT;定义数据段MESS 1 DB PERSONAL COMPUTER$;定义字符串,字节变量DATA ENDS;数据段结束EXTRA SEGMENT;定义扩展段MESS2 DB 17 DUP(?);定义17个字节的存储区EXTRA ENDS;扩展段结束CODE SEGMENT;定义代码段ASSUME CS:CODE,DS:DATAREA,ES:EXTRA;指定代码段、数据段及扩展段的段地址寄存器,START:MOV AX,DATA;送数据段首地址到AXMOV DS,AX;将AX内容送段寄存器DS。这两句共同完成“送数据段首地址到DS”MOV AX,EXTRA;MOV ES AX;这两句共同完成“送扩展段首地址到ES”LEA SI,MESS1;送MESS 1的符号地址到SI,使CPU找到源串地址LEA DI,MESS2;送MESS2的符号地址到SI,使CPU找到目的串地址MOV CX,17;使CX17,CX当计数器使用CLD;使DF0,方向标志清0,重复操作时,SI、DI自动加1,REP MOVSB;重复送字符串操作,将源串字符MESS l送到目的串MESS2的操作,直到CX0为止CODE ENDS;代码段结束 END START,4.在字符串中查找字符,【例5-5】在BLOOCK开始的数据块(假设在数据段)中查找字母“M”,如未找到,记寄存器DI0;如果找到了,在DI中存放查找次数,并将“M”字符所在位置存放在POINTER存储单元。DATA SEGMENT;定义数据段BLOOCK DB 64H;定义数据块CHAR DB M;定义字符,字节变量POINTER DD?;COUNT DB 64H;预置查找次数,一般设为数据块的总字符数,这里设为100。DATA ENDS;数据段结束 CODE SEGMENT ASSUME CS:CODE,DS:DATAREA,START:MOV AX,DATA;MOV DS,AX;送数据段首地址到DSMOV ES,AX;送扩展段首地址到ESMOV DI,OFFSET BLOOCK;送数据块BLOOCK的偏移地址到寄存器DIMOV CX,COUNT 将CX当计数器使用,预置查找次数COUNTMOV AL,“M”;将字符“M”ASCII码送寄存器ALCLD;使DF0,方向标志清0,DI自动递增1REPNE SCASB;SCASB把AL的内容与由DI指定的在附加段中的一个字节进行比较,但不保存结果,只根据结果置条件码ZF。CXCX1,CX0且ZF0时,重复操作字符串搜索指令SCASB,直到CX0(全部搜索完毕)或ZF1(若找到了,两字符的ASCII码值相等,差为0时)时为止JZ FOUND;ZF1时,表示若找到了,跳转到FOUND语句MOV DI,0;全部搜索完毕,尚未找到关键字“M”,将0送寄存器DI JMP DONE;跳转到DONE语句,FOUND:DEC DI;使DI减1 MOV POINTER,DI;将关键字“M”的地址送POINTER MOV BX,OFFSET BLOOCK;送数据块BLOOCK的偏移地址到寄存器BX SUB DI,BX;找到,送关键字“M”相对于BLOOCK的偏移地址的偏移量到DI INC DI;使DI加1;恢复DI的值,指向下一次DONE HLT;结束 END START,5.取子字符串,【例5-6】在字节字符串STR中搜索子串AM出现的次数,送寄存器BX。试编写其程序。分析问题:由题意可知,在字符串STR中搜索子串AM的方法是:首先在STR串中搜索字符A,找到后。则检查它的下一个字符是否是M。是,则(BX)十lBX,如果这时(CX)0,说明STR串还未搜索完再继续搜索A;如果不是M,在未搜索完时也要再继续搜索A。确定算法:采用重复送字符串操作,本题用REP MOVSB指令实现。用JMP指令实现循环。确定汇编语言程序的基本框架:可见,该汇编语言程序的基本框架至少要两个段:数据段和代码段。数据段中至少定义一个字符串变量STR,数据为字符,应选DB 类型。用寄存器DI定位。还有一个变量COUNT,定义为字符串长度。其中间结果放在寄存器AL,BX。,图5-1 取子字符串程序框图,画程序流程图:见图5-1。,编写程序,可以想得到,需要MOV、LEA、CMP、JE、JNE、INC和JMP等指令。最后要返回DOS。未想到的,在编写过程中随时添加,如CLD 指令等。为方便转移,程序中定义了多个标号。具体程序如下:DATA SEGMENTSTR DB KFAMAMNAAMAMAMAMAJMMAFKAMCOUNT EQU$-STR;DATA ENDSSTACK SEGMENT STACK DB 200 DUP(0)STACK ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK,START:MOV AX,DATAMOV DS,AX;数据段寄存器DS初始化MOV ES,AX;扩展段寄存器ES初始化LEA DI,STR;送字符串STR起始偏移地址到寄存器DI,用DI定位MOV CX,COUNT;将COUNT的值送计数器CXMOV BX,0;寄存器BX清零,MOV AL,A;将字符A的ASCII码送ALCLD;标志位DF清零P:REPNE SCASB;在STR串中搜索字符A,SCASB把AL的内容与由DI指定的在附加段中的一个字节进行比较,但不保存结果,只根据结果置条件码ZF。CXCX1,CX0且ZF0时,重复操作字符串搜索指令SCASB,直到CX0(全部搜索完毕)或ZF1(若找到了,两字符的ASCII码值相等,差为0时)时为止,JE A;搜索到,则转标号A处执行JMP OUT l;否则,转OUT l语句,结束A:CMP BYTE PTRDI,M;比较A后面的字符是否是MJNE B;不是,转标号B处执行INC BX;BX BX1,累加找到字符串的次数B:CMP CX,0JNE P;若STR串未搜索完,则继续搜索OUT l:MOV AX,4C00HINT 21HCODE ENDS;代码段结束END START,5.2 数据的分类和统计程序,数据的分类和统计也是一类非数值计算,主要用循环和分支程序解决,举例如下:【例5-8】在首地址为DAT的字数组中,存放着N个有符号数。第一,求出它们的平均值,并存入AX寄存器中;第二,求出数组中有多少个数的取值小于此平均值,并将计数结果存入BX寄存器中。分析问题:由题意可知,程序至少需要执行两次循环,两次的循环次数都是N次。另外,为了计数控制,再加一个循环。确定算法:两次循环不同,第一次循环累加N次再作除法,求平均值。第二次作比较循环。循环次数是N次。故用循环次数作为循环的控制条件,再配合使用LOOP指令。循环控制采用计数控制。画程序流程图:略。,返回本节,确定汇编语言程序的基本框架:共三个循环体。汇编语言程序的基本框架至少要两个段:数据段和代码段。数据段中至少定义2个变量:一个数组变量DAT,共N个数据,设为16位数,选DW 类型,使用寄存器SI定位。还有一个数N,为数组长度。计数器用CX。其中间结果分别放在寄存器AX和BX。存放转移指令的表JADT2在代码段中编写程序。本程序想向读者说明,用LOOP指令,结合采用无条件转移指令和条件转移指令,也可以实现程序的循环。可以想得到,需要MOV、LEA、CMP、JMP、JG、JL等指令。最后要返回DOS。,具体程序如下:DATA SEGMENTDAT DW Al,A2,An;定义数组DATN EQU$DAT;定义数组DAT长度DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART:MOV AX,DATAMOV DS,AX;数据段初始化XOR AX,AX;AX清零,用于存放数据累加和MOV CX,N;送循环次数N到寄存器CXLEA SI,DAT;送数组变量起始偏移地址到寄存器SI,用SI定位,LOP l:ADD AX,SI;循环体1。对数组变量DAT的数据累加,先从第一个数据开始ADD SI,2;SISI2,加上下一个数据字LOOP LOP l;计数控制,CXCX1,若CX0,循环到LOP l。直到CX0MOV BX,N;送数N到寄存器BXXOR DX,DX;DX清零,扩展到32位IDIV BX;计算平均值,结果放在AXXOR BX,BX;BX清零,用于存放小于平均值个数LEA SI,DAT;送数组变量起始偏移地址到寄存器SI,用SI定位MOV CX,N;循环次数,LOP2:CMP SI,AX;循环体2。数组SI中的数与平均值AX比较JGE LOP3;若大于或等于,转LOP3标号INC BX;个数加1LOP3:ADD SI,2;循环体3。SISI2,到下一个数据字LOOP LOP2;计数控制MOV AH,4CHINT 21HCODE ENDS END START,【例3-17】已知数组A中包含15个互不相等的字节整数,数组B中包含20个互不相等的字节整数。试编制一程序,将既在A中又在B中的整数存放到数组C中。解:为了保证循环程序能正常运行而必须作的准备工作,在循环开始时往往要给循环过程置以初态,即赋一个初值。循环初态又可以分成两部分,一是循环工作部分初态,另一是循环结束条件的初态。例如,要设地址指针,要使某些寄存器清零,或设某些标志等等。循环结束条件的初态往往置以循环次数置初态也是循环程序的重要的一部分,不注意往往容易出错。分析问题:由题意可知,数组A中的15个数都要分别与数组B中的20个数作比较。显然,应该把数组A的循环作为外循环,并且要循环15次;而数组B中的循环应该是内循环,循环次数是20次。确定算法:两次循环,循环次数均是已知的。故用循环次数作为循环的控制条件,再配合使用LOOP指令。循环控制采用计数控制。,画程序流程图:略。确定汇编语言程序的基本框架:共三个循环体。汇编语言程序的基本框架至少要两个段:数据段和代码段。数据段中至少定义3个数组变量A、B、C,因数据是字节整数,选DB 类型,分别使用寄存器SI、BX、DI定位。数组变量C是15个字节的数据缓冲区。内外循环计数器都用CX,在内循环前要注意保护外循环次数(压栈)。其中间结果放在寄存器AL。编写程序。本程序想向读者说明,用LOOP指令,结合采用无条件转移指令和条件转移指令,也可以实现程序的循环。可以想得到,需要MOV、LEA、CMP、JMP、JNZ、PUSH、POP等指令。最后要返回DOS。,具体程序如下:DATA SEGMENTA DB Al,A2,A15B DB B1,B2,B20C DB 15 DUP(?)DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART:MOV AX,DATAMOV DS,AXLEA SI,A;送数组A的起始偏移地址,也是外循环工作初值到SIMOV CX,15;外循环次数,外循环结束控制初值LEA BX,C;送数组C的起始偏移地址,也是内循环工作初值到BX,LOP l:MOV AL,SI;外循环体开始PUSH CX;因内循环次数也用CX表示,所以要先保存外循环次数MOV CX,20;内循环次数,内循环控制初值,也用CX表示LEA DI,B;送数组B的起始偏移地址,也是内循环工作初值到DI LOP2:CMP AL,DI;内循环体,AL(即数组A的第一个数据)与数组B的数比较JNZ NEXT;不相等则转移到标号NEXTMOV BX,AL;相等则存入数组CINC BX;修改内循环参数,数组C的地址加1JMP MEXT;退出内循环,NEXT:INC DI;修改内循环参数,数组B的地址加1 LOOP LOP2;CXCX1,若CX0,循环到LOP 2。直到CX0 内循环控制,内循环次数减1MEXT:INC SI;修改外循环参数,数组A的地址加1 POP CX;恢复外循环次数的值 LOOP LOP l;外循环控制,外循环次数减l MOV AH,4CH INT 2lHCODE ENDS END START,如果使用串操作指令来实现,那么程序段应该改写为:DArA SEGAMENTA DB A1,A2,A15B DB B1,B2,B20C DB 15 DUP(?)DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART:MOV AX,DATAMOV DS,AXMOV ES,AX;串操作必须设置ESLEA SI,ALEA BX,CMOV CX,15:循环次数LOPl:PUSH CX,;保存循环次数(可用MOV DX,CX)MoV CX20;重复搜索次数MOV AL,SILEA DI,BCLD;DI增量,本指令不能少REPNZ SCASB;不相等重复搜索JNZ LOP2;没找到相等的数MOV BX,ALINC BXLOP2:POP CX;恢复外循环次数(可用MOV CX,DX)INC SILOOP LOPl;CXCX,CX0循环MOV AH,4CHINT 21HCODE ENDSEND START,【例3-11】将数据段的数据按正、负分开,分别送到两个缓冲区,程序如下(数据段的定义部分省略):START:MOV SI,OFFSET BLOCK;将数据段的偏移地址送SI,即将SI指向数据区 MOV DI,OFFSET PLUS-DATA;DI指向正数缓冲区 MOV BX,OFFSET MINUS-DATA;BX指向负数缓冲区 MOV CX,COUNT;将数据字节送CX CLD;将DF清0GOON:LODSB;取串指令 TEST AL,80H;字节最高位为1(表示是负数)吗?JNZ MINUS;是,则转移到MINUS语句 STOSB;否则,执行存入串指令STOSB JMP AGAIN;跳转到AGAIN语句MINUS:XCHG BX,DI;STOSB;XCHG BX,DIAGAIN:LOOP GOON HLT,例510将首地址为DAT的n个无序字数据从小到大排序。解:将无序的数据进行排序,这在数据检索中有着广泛的用途。下面用“冒泡排序”算法对n个数据进行排序。“冒泡排序”算法的含义是:从第一个数开始依次对相邻的两个数做比较。如果它们符合由小到大的次序,那么不做任何操作;如果不符合由小到大的次序,则就交换这两个数的位置。这样比较了一轮之后,就会使n个数中的最大者排在了它应该在的位置上(最后面)。从而进入下一轮比较。这样,应该把不同的轮作为一个外循环,而每一轮进行的两两比较作为一个内循环。分析一下可以看出,既然在做了第一轮的(n-1)次比较之后,最大的数已放到了最后,所以做第二轮时,只需在前面的n1个数据里进行(n2)次比较。由于每做一轮比较,就使一个数据到达它应在的位置,如此类推下去,外循环总共要做(n-1)轮,就可以使n个数据完成排序。具体地说,5个数的排序需要进行4轮比较,第一轮需要两两比较4次;第二轮时,需要两两比较3次;如此等等。假定5个数最初的排列是8,5,16,84,2,图5-6给出了整个排序进行的情况。,图5-6排序操作过程示意图:,DArA SEGMENTDAT DW Al,A2,AnDATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART:MOV AXDATAMOV DS,AXMOV CX,N l;外层和内层的循环次数相同LOP l:XOR SI,SI;外循环体,设置内循环参数PUSH CX;保存外循环次数LOP2:MOV AX,DATSI;内循环体CMP AX,DATSI+2;DATSI小于等于DATSI+2?JLE LOP3;是,转移XCHG AX,DATSI+2;两数交换,大的放后面MOV DATSI,AX;小的放前面,LOP3:ADD SI,2;指向下一个数LOOP LOP2;内循环控制POP CX;恢复外循环次数LOOP LOPl;外循环控制MOV AH,4CHINT 21HCODE ENDSEND START如果n=3,可以有下面的几种排序方法。第一种是设把3个有符号数分别放在寄存器AX,BX和DX中,那么排序的程序段可以是:MOV CX,2LOPI:CMP AX,BXJLE LOP2XCHG AX,BX,LOP2:CMP BX,DXJLE LOP3XCHG BX,DXLOOP LOPlLOP3:如果把3个有符号数分别放在寄存器AX,BX和CX中,那么排序的程序段可以改写为:LOPI:CMP AX,BXJLE LOP2XCHG AX,BXLOP2:CMP AX,CXJLE LOP3XCHG AX,CXJMP LOPlLOP3:当AX=3,BX=2,CX4时,程序第一次执行到JLE LOP3就会结束循环。,5。4循环程序设计示例例5-11用非压缩BCD码调整指令求两个4位的ASCII数串9888、7956之和,并将结果以十进制格式显示在屏幕上。解:ASCII码加法调整指令AAA将进位累加到AH中,而且置进位标志,所以可用带进位加指令得到低位相加时的进位,只有最高位的进位要从AH获得。因此,每次循环时要将AH清O,只保留最后一次用AAA调整指令所得到AH的值(0或1)。DATA SEGMENTASC1 DB 9888;高位存低地址,低位存高地址ASC2 DB7956DATA ENDSCODE SEGMENTASSUME CS:C0DE,DS:DATASTART:MOV AX,DATAMOV DS,AXMOV SI,3;从高地址开始取低位数MOV CX,4CLC;清进位,LOPl:M0V AH,0;只要最高位相加时的进位MOV AL,ASClSIADC AL,ASC2SI;带进位加AAA;ASCII码加法调整,进位累加到AH中PUSH AX;结果入栈,AL低4位是BCD码,高4位清0DEC SILOOP L0PlMOV CX,4;出栈循环计数CMP AH,1;最高位相加有进位?,JL LOP2;无进位转移MOV AL,AHPUSH AX;最高进位位入栈INC CX:出栈计数加1LOP2:POP DX;先进后出ADD DL,30H;转换为ASCII码MOV AH,02H;显示INT 2lHLOOP LOP2MOV AH4CHINT 21HCODE ENDSEND START,例5-12编写一个程序,求出首地址为DAT的100个16位有符号数的数组中的最小偶数,并将它存放到DBT的字单元中。若无偶数,则该单元存0。解:算法的思路是先将AX清0,然后开始在数组中寻找偶数。如果数组中没有偶数,就将Ax的值存入DBT的字单元。如果有的话,将第一个找到的偶数存入Ax当作当前的最小偶数,然后与数组中后面的偶数比较,用小的偶数更换Ax,直到与最后一个数比较完毕,Ax中的数就是最小偶数。整个过程有两种操作:一是寻找偶数,二是比较偶数的大小。只有当Ax已经存入偶数后才需要比较。为此,设置Bx寄存器的值作标志。如果Bx=O,把找到的偶数存入Ax,同时对Bx置1;如果Bx=1,则将再次寻找到的偶数与Ax中的当前最小偶数比较。,DATA SEGMENTDAT DW Al,A2,A100DBT DW 0N EQU(DBT-DAT)2DATA ENDSCODE SEGM【ENTASSUME CS:CODE,DS:DATASTART:MOV AX,DATAMOV DS,AXLEA SI,DAT;取数组首地址XOR AX,AX;用AX 存放当前最小偶数XOR BX,BX;用BX作第一次找到偶数标志位MOV CX,N;循环控制初值LOP O:TEST WORD PTRSI,l;SI是偶数?JNZ LOP2;不是,转移CMP BX,0;是第一次找到的偶数?,JNZ LOPl;不是INC BX;标志置lMOV AX,SI;取第一个偶数送AXJMP LOP2LOPl:CMP SI,AX;S1大于当前最小偶数?JGE LOP2;是,转移MOV AX,SI;更换为当前最小偶数LOP2:ADD SI,2;修改操作数地址LOOP LOPO;循环LOP3:MOV DBT,AX;存入最小偶数或0MOV AH,4CHINT 21HCODE ENDSEND START,例5-13在首地址为DAT的字数组中存放了n个有符号数。求出数组中绝对值最大的数并将它存入DATl单元。解:与一般的求最大值问题不同,负数的绝对值是该负数的补码,求补后才能进行绝对值的比较。所以,事先需要将该数放到另一寄存器保存起来。程序中需要设置两个参数,一个是当前绝对值最大的数,一个是当前最大的绝对值。DATA SEGMENTDAT DW Al,A2,AnDATl DW?N EQU(DATlDAT),2DAI