第五章循环与分支程序设计1、编制汇编语言程序的步骤如下:分析题意,确定算法根据算法画出程序框图根据框图编写程序上机调试2、程序有顺序、循环、分支和子程序四种结构形式5.1顺序结构及简单程序设计程序设计中最基本的结构是如图所示的顺序结构,它只有一个起始框、一个结束框和一至多个执行模块。具有顺序结构的程序叫做简单程序。顺序结构中的执行模块可以是一个指令、一条语句或完成某一功能的程序。简单程序执行的特点是其中的指令或语句是按顺序执行的,没有分支或循环。开始结束例:设置光标到屏幕左上角。SET_CURPROCMOVAH,2MOVBH,0MOVDX,0INT10HRETSET_CURENDP这个程序是顺序执行的,一条指令执行后顺序执行紧接其后的另一条指令。实际上许多程序片段都具有顺序结构。5.2循环程序设计5.1.1循环程序的结构形式DO-UNTIL结构不满足满足条件循环体循环初始化不满足DO-WHILE结构满足条件循环体循环初始化DO-WHILE结构是先判断后执行的结构,它把对循环控制条件的判断放在循环的入口,先判断控制条件,若满足控制条件(例循环次数不为0)就执行循环体,否则退出循环。DO-UNTIL结构则是先执行后判断的结构,它先执行循环体然后再判断控制条件,若满足控制条件则继续执行循环体,否则退出循环。这两种结构一般可以随习惯使用,但在初始循环次数可能为0的情况下则必须使用DO-UNTIL结构。5.1.2循环程序设计方法无论使用哪种循环结构,循环程序一般应包括以下几部分:循环初始化。它包括设置循环次数的初始值、地址指针的初始设置等。循环体。这是循环工作的主体,包括要重复执行的操作,以及循环的修改部分。修改部分包括地址指针的修改、循环控制条件的修改等。循环控制部分。它是控制循环的关键,判断循环条件满足与否。特别要注意循环入口和循环次数的正确设置、地址指针及循环控制条件的修改等。否则会得不到期望的结果。例5.1试编制一个程序,把BX寄存器中的二进制数以十六进制的形式显示在屏幕上。以binihex.asm为文件名,建立源程序如下:;binihex.asmprognamsegment;定义代码段mainprocfarassumecs:prognamstart:;程序从此处开始执行;为正常返回DOS而设置堆栈pushdssubax,axpushax;下面是程序的主要部分movch,4;4组二进制数rotate:movcl,4;每组4个二进制位rolbx,cl;把bx循环左移4位moval,bl;暂存bl到al中andal,0fh;仅保留al的低4位addal,30h;转换成ASCII码cmpal,3ah;要显示的数大于9?jlprintit;如果数在0~9之间则显示addal,7h;数在A~F之间则调整printit:movdl,al;把要显示字符的ASCII码送dlmovah,2;功能号2送ahint21h;DOS功能调用decch;(ch)-1jnzrotate;4组都处理完?否,循环处理下一组ret;返回DOSmainendp;主程序main结束prognamends;代码段结束endstart;结束汇编例:在字型无序表中找出最大数和最小数,并分别存入MAX和MIN单元。算法分析:把表中第一个元素分别作为最大数和最小数,与下一个元素比较,若下一个元素比该元素大,则把下一个元素作为最大数,继续进入下一轮比较;若下一个元素比该元素小,则把下一个元素作为最小数,继续进入下一轮比较……直至遍历整个表,最后保留下来的两个数就分别是表中的最大数和最小数。本例采用DO_UNTIL结构实现。程序:STACKSGSEGMENTSTACK'STK'DW32DUP('S')STACKSGENDSDATASEGMENTBUFFERDW500,30,56,77,999,67,433,5675,0,9999;无序表DW3455,6578,32766,8,0,32560,45,889,5665,09CNDW($-BUFFER)/2;元素个数MAXDW?;存放最大数单元MINDW?;存放最小数单元DATAENDSCODESEGMENTMAINPROCFARASSUMECS:CODE,DS:DATAPUSHDSXORAX,AXPUSHAXMOVAX,DATAMOVDS,AXLEASI,BUFFER;初始化地址指针MOVCX,CN;元素个数MOVAX,[SI];取第一数MOVMAX,AX;初始化最大数MOVMIN,AX;初始化最小数COMP:ADDSI,2;修改地址指针MOVAX,[SI];取下一个数CMPAX,MAX;与当前的最大数比较JLNEXT;若小于转MOVMAX,AX;若大于则把此数作为最大数保存JMPSHORTLOPNEXT:CMPAX,MIN;与当前的最小数比较JGLOP;若大于转MOVMIN,AX;若小于则把此数作为最小数保存LOP:LOOPCOMP;决定循环继续还是终止RETMAINENDPCODEENDSENDMAIN例5.4将正数N插入一个已整序的字数组的正确位置。该数组的首地址和末地址分别为ARRAY_HEAD和ARRAY_END,其中所有数均为正数且已按递增的次序排列。注意:在考虑算法时,必须把可能出现的边界情况考虑在内;定义数据段datareasegmentxdw?array_headdw23,37,49,52,65,78,99array_enddw105ndw32datareaends;定义代码段prognamsegmentmainprocfar;主程序部分assumecs:prognam,ds:datareastart:;程序从此处开始执行pushdssubax,axpushaxmovax,datareamovds,ax;程序的主要部分movax,nmovarray_head-2,0ffffh;-1送array_head-2单元movsi,0compare:cmparray_end[si],axjleinsertmovbx,array_end[si]movarray_end[si+2],bxsubsi,2jmpshortcompareinsert:movarray_end[si+2],axretmainendp;主程序main结束prognamendsendstart例:自定义一个按降序排列的字型数组,在数组中查找指定的数字,若找到在屏幕上显示“Duplication!”,否则插入该数字在适当位置并继续保持数组有序,且显示“Inserted!”。算法:先使用字符串指令进行块查找,若找到则显示“Duplication!”后退出。若未找到则从数组中第一个数开始比较。由于数组是降序的,所以当数组中当前元素比指定数字小时,说明该数组中无指定数字,则应插入之,且显示“Inserted!”。否则把数据前移一个位置,为以后要插入的数据腾出空间,继续循环对下一个数进行比较…...这是一个初始循环次数不定、根据条件控制循环的例子程序:DATASEGMENTPRTDB'Duplication','$'INSDB'Inserted!','$'XDW?;为数据移动预留空间TABDW889,754,589,546,52,31;降序数组CTEQU($-TAB)/2;元素个数NDW234;要插入的数字DATAENDSCODESEGMENTMAINPROCFARASSUMECS:CODE,DS:DATAPUSHDSSUBAX,AXPUSHAXMOVAX,DATAMOVDS,AXMOVES,AXLEADI,TAB;装入表首址MOVAX,N;要插入的数字MOVCX,CT;个数CLDREPNZSCASWJEA;找到转MOVSI,0COMPARE:CMPTAB[SI],AX;比较JLBMOVBX,TAB[SI];元素前移为插入的数字腾位置MOVTAB[SI-2],BXADDSI,2;修改地址指针JMPSHORTCOMPAREA:MOVAH,9HLEADX,PRTINT21HJMPEXITB:MOVTAB[SI-2],AX;插入元素MOVAH,9LEADX,INSINT21HEXIT:RETMAINENDPCODEENDSENDMAIN例5.设数组X、Y中分别存有10个字型数据。试实现以下计算并把结果存入Z单元。Z1=X1+Y1Z2=X2+Y2Z3=X3-Y3Z4=X4-Y4Z5=X5-Y5Z6=X6+Y6Z7=X7-Y7Z8=X8-Y8Z9=X9+Y9Z10=X10+Y10分析:设想按Z10、Z9……Z1的计算顺序把它们的操作符自左至右排列起来,并把加用0表示,减用1表示,则十个操作符数字化后得到一串二进制位0011011100,把它放入一个字型内存变量中,其高6位无意义(此处用0填充),这种存储单元一般被叫做逻辑尺。计算时按照Z1……Z10顺序,先求Z1的值。每次把逻辑尺右移一位,对移出位进行判断,若该位为0则加,为1则减。于是就可以用一个分支加循环的混合程序实现所要求的功能。YN初始化循环计数值i=0RULEi=1?Xi+YiXi-YiYZi←结果i=i+1,循环次数减1N循环计数值=0?开始结束;定义数据段datareasegmentxdwx1,x2,x3,x4,x5,x6.x7,x8,x9,x10dwy1,y2,y3,y4,y5,y6,y7,y8,y9,y10zdwz1,z2,z3,z4,z5,z6,z7,z8,z9,z10logic_ruledw00dchdatareaends;定义代码段prognamsegmentmainprocfarassumecs:prognam,ds:datareastart:pushdssubax,axpushaxmovax,datareamovds,axmovbx,0movcx,10movdx,logic_rulenext:movax,x[bx]shrdx,1jcsubtractaddax,y[bx]jmpshortresultsubtract:subax,y[bx]result:movz[bx],axaddbx,2loopnextretmainendpprognamendsendstart总结:这种设置逻辑尺的方法非常有用。例如要传输一批数据(定义为一个数组),该数组中含有多个0元素,为了节省存储空间和传输时间,可以选用合适的数据结构。比如可以使用压缩数据及逻辑尺的方法,把所有元素按下标顺序排列,并各用1个bit表示。设0元素用0表示,非0元素用1表示。存储时只需保存非0元素(压缩数组)和逻辑尺,当进行数据传输时,若逻辑尺相应位为1,则从压缩数组中取到非0数据并传送。若逻辑尺相应位为0时,只送一个标志,在接收方直接生成数字0,这样可以提高传输效率5.1.3多重循环程序设计有些比较复杂的问题使用一重循环可能无法解决,此时就需要设计多重循环程序。对于多重循环程序设计,需要注意循环初始设置、循环入口、循环控制条件的修改等;还要注意内、外循环体不能交叉;在每次通过外层循环再次进入内层循环时,初始条件必须重新设置一个简单延时程序:(双重循环)movcx,100n_start:movdx,0ffffhn_loop:decdxjnzn_loopdeccxjnzn_start外循环初始化内循环初始化内层循环体外层循环体内循环结束外循环结束NNYY例1:有一个首地址为A的N字数组,请编程使该数组中的数按照从大到小的次序排序分析:采用起泡排序算法。从第一个数据开始依次对相邻两个数进行比较,如次序对则不做任何操作;如次序不对则使这两个数交换位置。第一遍进行(N-1)次比较后最好的数放到了最后;第二遍进行(N-2)次比较;……总共最多进行(N-1)遍比较就可以完成排序还可以采用设立测试标志的方法来进行起泡排序;定义数据段dsegsegmentnequ5;数组中数的个数adwndup(?)dsegends;定义代码段csegsegmentmainprocfarassumecs:cseg,ds:dse