第12章表的处理.ppt

上传人:本田雅阁 文档编号:2576732 上传时间:2019-04-11 格式:PPT 页数:75 大小:261.51KB
返回 下载 相关 举报
第12章表的处理.ppt_第1页
第1页 / 共75页
第12章表的处理.ppt_第2页
第2页 / 共75页
第12章表的处理.ppt_第3页
第3页 / 共75页
亲,该文档总共75页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第12章表的处理.ppt》由会员分享,可在线阅读,更多相关《第12章表的处理.ppt(75页珍藏版)》请在三一文库上搜索。

1、第12章 表的处理,12.1 定义表 12.2 表的直接存取 12.3 表的搜索 12.4 转换指令XLAT 12.5 显示十六进制数和对应的ASCII字符 12.6 数据排序程序 12.7 TYPE、LENGTH和SIZE运算符,12.1 定 义 表,为了便于对表的处理,首先要定义表,组织好表的结构,即把表的内容按一定规律组织起来。这样编程时就可以根据一定规律存取表中各项的内容。表的定义、组织没有固定的方法,完全是按表的内容和用途而定。表的元素(内容)可以是一个数,也可以是一个字符或字符串。,例如:以英文月份的缩写定义一个表,可以是如下的格式: MONTAB DB JAN, FEB, MAR

2、,DEC 这个表具有连续、数据项等长的特点,处理起来就很方便。只要指定月份,就很容易查出该月的英文月份的缩写。,12.2 表的直接存取,假设使用者从键盘输入一个月份的号码,如03,程序负责把它转换成文字型的月份名称的缩写MAR。完成这个工作的程序,必须定义一个表以存放各月份的名称,要求表中的每一项长度一样(即3)。所以这个表必须定义为下列形式:,MONTAB DB JAN DB FEB DB MAR ,表中的第一项JAN的偏移地址是MONTAB0,FEB的偏移地址是MONTAB3,MAR的地址是MONTAB6。为了找到3月份在表中的月份缩写名称,程序必须做下列操作: (1) 输入月份3的ASC

3、II码33,33转换成二进制的3。 (2) 从月份中减去1:3-12。 (3) 将差值乘以3(月份字符长度):236。,(4) 将所得的乘积加到MONTAB的偏移地址:MONTAB6,结果即为3月份MAR的偏移地址。 下例是完成上述工作的程序。,例12.1 从键盘输入一个数字月份,显示其对应的英文缩写。 源程序清单如下: ; filename:L121. ASM ; DATA SEGMENT THREE DB 3 MONIN DB 11 ;假设已输入的月份,ALFMON DB ?, $ MONTAB DB JAN, FEB, MAR, APR, MAY, JUN DB JUL, AUG, SE

4、P, OCT, NOV, DEC DATA ENDS ; CODE SEGMENT ASSUME CS:CODE,DS:DATA,ES:DATA START: MOV AX,DATA,MOV DS,AX MOV ES,AX CALL C10CONV CALL D10LOC CALL F10DISP MOV AH,4CH INT 21H ; ASCII码转换成二进制 ; ,C10CONV PROC MOV AH,MONIN MOV AL,MONIN+1 XOR AX,3030H CMP AH,00,JZ C20 SUB AH,AH ADD AL,10 C20: RET C10CONV ENDP

5、; Locate month table ; D10LOC PROC,LEA SI,MONTAB DEC AL ;月份减1 MUL THREE ADD SI,AX ;形成该月英文的首地址 MOV CX,03 CLD LEA DI,ALFMON REP MOVSB ;传送3个字符 RET,D10LOC ENDP ; Display alpha month ; F10DISP PROC LEA DX,ALFMON MOV AH,09 ;显示月份英文缩写 INT 21H RET F10DISP ENDP CODE ENDS END START,说明:例12.1假设使用者已用另外一个程序接受了输入的A

6、SCII月份数,并存在MONIN单元内。 如果上述各数据项长度不等长,那么取出中间数据项就很麻烦。例如,要求显示英文月份全名,此时需要构造有规律的表;方法是取最长月份的名作为各月份项的长度,不足者补空格,然后就可按照上述方法处理编写程序。,因为例12.1的方法是直接计算表中的某项地址,然后存取,而不需要将整个表从头到尾搜寻一遍,所以称为表的直接存取法。 直接存取法虽然很有效,但是它只适用于各项连续的表;例如,表的各项是1,2,3 的顺序,或606,607,608,甚至可以是5,10,15 。但是,通常实际使用时不会全是有如此规律的表。,12.3 表 的 搜 索,表的搜索方法有直接搜索法、顺序搜

7、索法、折半搜索法等。 直接搜索法就是要搜索的内容和它在表中的位置存在有一定的规律,也就是说可用某一公式表示获得这种规律。这种方法搜索最快,但要求表中各数据项有规律性。在定义表时尽量要满足某种规律,然后才能使用,见例12.1。,顺序搜索法通常适用于对无规律的数组进行搜索,表中的元素之间或元素与地址之间无规律可循。此种方法只能从表的开头开始逐项搜索,这种方法的平均比较次数为(n+1)/2次,所以速度慢,效率低。 折半搜索法适用于已排序的表,这种方法搜索次数少,效率高。,例12.2 顺序搜索表。设有一个包含若干个字节的数组,首地址为A;要求编写程序,查找其中是否存在数“8”。若存在,显示“Y”;否则

8、,显示“N”。 源程序清单如下:,; filename:L122.ASM ; DATA SEGMENT A DB 1,3,20,5,6,2,8 C EQU $A,DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA,ES:DATA START: MOV AX,DATA MOV DS,AX MOV ES,AX MOV CX,C LEA DI, A MOV AL,8 CLD,REPNZ SCASB JZ FOUND MOV DL,N JMP DISP FOUND: MOV DL,Y DISP: MOV AH,2 INT 21H MOV AH,4CH INT 2

9、1H CODE ENDS END START,例12.3 对元素长度超过两个字节的表进行搜索。 当表中各项的长度超过两个字节时,就必须用REPE CMPS指令来比较。假设,有这样一种货物号与货物名表:3个字节长度的货物号,9个字节长度的货物名,见例12.3数据段。STOKNIN是数据段的第一栏,表示要搜寻的货物号;STOKTAB是第二栏,表示货物表的开始,它们在存储器中的排列情形如下: 货物表: 123 035 Excavators 038 Lifters 049 Presses 偏移地址: 00 03 06 16 19 29 32,表的最后使用了一项“999”作为搜寻结束的标识。表中的每一项

10、内容以下列的方法与STOKNIN作比较: 表中之项 STOKNIN 比较结果 035 123 小于,检查下一项 038 123 小于,检查下一项 049 123 小于,检查下一项 102 123 小于,检查下一项 123 123 等于,搜索成功,例12.3的程序所使用的CMPSB指令,可以一个字节一个字节逐个比较,直到不相等为止,同时它也可以将寄存器SI和DI自动加1。 首先,CX被初始化为03,而SI和DI所存的偏移地址分别是03和00。当表中的第一项和STOKNIN比较时(035:123)会在第一个字节比较完之后结束;此时SI是04,DI是01,而CX是02。为了能正常地进行下一项的比较,

11、SI应该是16,DI应该是00。,要获得正确的DI内容,可以再将STOKNIN的地址传送给DI;若要使SI能得到正确的地址,它应由上一次比较停在哪一项之后而决定;还应考虑CX当前的值,即有多少字节未作比较,此时CX是02。SI的当前值加上CX的当前值再加上货物名的长度,就可以得到下一项在表中的正确地址,即 CMPSB执行后SI内的值: 04 加CX的当前值: 02 加货物名的长度: + 10 下一项的偏移地址: 16,由于CX所含的值是剩下的未作比较的字节数,所以,以上的计算方法适用于所有的情形。在比较了1、2或3个字节之后,当比较的结果相等时,CX的值是00,此时SI也就是所要的货物名的地址

12、了。 例12.3的源程序清单如下: ; filename:L123.ASM ; DATA SEGMENT STOKNIN DB 123,STOKTAB DB 035, Excavators ;Start of table DB 038, Lifters DB 049, Presses DB 102, Valves DB 123, Processors DB 127, Pumps DB 999, 10 DUP( ) ;End of table DESCRN DB 10 DUP(?),DATA ENDS ; CODE SEGMENT ASSUME CS:CODE,DS:DATA,ES:DATA S

13、TART: MOV AX,DATA MOV DS,AX MOV ES,AX CLD LEA SI,STOKTAB A20: MOV CX,03,LEA DI,STOKNIN REPE CMPSB JE A30 JA A40 ADD SI,CX ADD SI,10 JMP A20 A30: MOV CX,05 LEA DI,DESCRN REP MOVSW JMP A50,A40: CALL R10ERR A50: MOV AH,4CH INT 21H ; R10ERR PROC ; RET R10ERR ENDP CODE ENDS END START,12.4 转换指令XLAT,XLAT指令

14、可以将一个字节的值,转换成另一个已经预先定义在一个表中的值。例如,可以利用XLAT指令把十六进制数转换成其对应的ASCII码,或把ASCII码转换成十六进制数。,例12.4是把十六进制数(Hex)转换成ASCII码。要使用XLAT指令,必须先定义一个转换表,用以存放十六进制数对应的ASCII码表,如: XLTAB DB 30H,31H,32H,33H,34H,35H,36H,37H DB 38H,39H,41H,42H,43H,44H,45H,46H,在使用XLAT指令之前,要先将表格的首地址放入BX寄存器内,要转换的字节即 十六进制数,也应预先放入AL寄存器中;指令执行后可在AL中得到转换后

15、的代码(ASCII码)。XLAT指令利用AL寄存器内的值当作相对位移值,再加上BX的值,即可得到正确的地址。假设Hex是5,那么计算所得的地址是XLTAB5,XALT根据这个地址从表中查得35H,取代了AL原先的5。所以这种方法被称为查表法。,例12.4 用查表法将一位十六进制数转换成相应的ASCII码。 源程序清单如下:,; filename:L124.ASM ; DATA SEGMENT,XLTAB DB 30H,31H,32H,33H,34H,35H,36H,37H DB 38H,39H,41H,42H,43H,44H,45H,46H HEX DB 5 ASC DB ? DATA END

16、S ; CODE SEGMENT,ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX LEA BX,XLTAB MOV AL,HEX XLAT MOV ASC,AL MOV AH,4CH INT 21H CODE ENDS END START,12.5 显示十六进制数和对应的ASCII字符,例12.5几乎可以显示所有的ASCII字符和所对应的十六进制数。例如,Hex (十六进制) 53的ASCII码是大写字母S,程序就会显示53 S。完整的屏幕显示是一个1616 的矩阵。,显示ASCII码符号比较容易,但要将十六进制数显示出来,所涉及的技巧就

17、比较多。例如,要用ASCII码显示Hex 53,就必须将Hex 53,转换成Hex 35 33;要显示Hex 00,就必须将00转换成Hex 3030,依次类推。,这个程序先把HEXCTR内存单元初始化成00,然后将它逐一加1。子程序C10HEX把HEXCTR分成两个十六进制数。假设HEXCTR的内容是4F,C10HEX先取出Hex 4,把它当作转换指令所需要的XLATAB表的指针,转换后所得的值Hex 34放在AL内。然后C10HEX再取出F,转换成Hex 46。这个过程的运算结果是Hex 34 46,便可以显示出4F。显示结果在内存的存放格式是5个为一组(如第一项:2位十六进制数(00)、

18、空格、对应的ASCII字符、空格),以80个字符为一行显示。例如,从DISPROW开始:,十六进制数 字符 十六进制数 字符 十六进制数 字符 内存内容:30 30 20 00 20 30 31 20 01 20 30 32 20 02 20 显 示:0 0 0 1 0 2 表示空格。无法显示的字符均用空格(20)代替,因为DOS功能调用40H会将1AH当作一行的结束,所以程序将它转换成20H(空格)。,例12.5 显示十六进制数及其对应的ASCII字符。 程序清单如下:,; filename:L125.ASM ; DATA SEGMENT DISPROW DB 16 DUP( ),13 HE

19、XCTR DB 00 XLTAB DB 30H,31H,32H,33H,34H,35H,36H,37H DB 38H,39H,41H,42H,43H,44H,45H,46H DATA ENDS,; CODE SEGMENT ASSUME CS:CODE,DS:DATA,ES:DATA START: MOV AX,DATA MOV DS,AX MOV ES,AX CALL Q10CLR ;清除屏幕 LEA SI,DISPROW,A20LOOP: ALL C10HEX ;转换 CALL D10DISP ;显示 CMP HEXCTR,0FFH ;是最后的十六进制变量0FFH吗? JE A50 ;是则

20、终止程序 INC HEXCTR ;不是则下一个十六进制加1 JMP A20LOOP ;循环 A50: MOV AH,4CH INT 21H,; C10HEX PROC ;十六进制转换成ASCII码 MOV AH,00 MOV AL,HEXCTR ;取得一对十六进制数 SHR AX,CL ;右移 LEA BX,XLTAB ;设表的首地址 MOV CL,04 ;设移位次数 XLAT ;查表转换 MOV SI,AL ;存储左边的字符,MOV AL,HEXCTR SHL AX,CL ;左移十六进制数 SHR AL,CL XLAT ;查表转换 MOV SI+1,AL ;存储右边的字符 RET C10HE

21、X ENDP ; ,D10DISP PROC ;显示 MOV AL,HEXCTR MOV SI+3,AL CMP AL,1AH ;被显示的字符是1AH JE D20 ;07H10H均替换成20H CMP AL,07H JB D30 CMP AL,10H JAE D30,D20: MOV BYTE PTR SI+3,20H D30:,ADD SI,05 ;指向下一个显示项 LEA DI,DISPROW+80 CMP DI,SI JNE D40 MOV AH,40H ;请求显示调用 MOV BX,01 ;设备号显示器 MOV CX,81 ;显示整个行 LEA DX,DISPROW,INT 21H

22、LEA SI,DISPROW ;重置显示地址 D40: RET D10DISP ENDP ; Q10CLR PROC ;清屏 MOV AX,0600H MOV BH,07 ;颜色设置,MOV CX,0000 MOV DX,184FH INT 10H RET Q10CLR ENDP ; CODE ENDS END START,12.6 数据排序程序,在日常生活中,许多情况下都要用到排序,例如,图书编号、教室编号、学生编号等。有序的事情处理会比较方便,对表也一样,无序表的访问是非常费时的。为了提高对表的访问效率,常常将表组织成有序表。将无序表中的数据项按照一定的顺序重新排列,这个过程就是排序。,表

23、的排序方法有很多种,有的很有效但不够简洁,有的很简洁但却没有效率。本节所介绍的排序方法效率比较高,而且可以用于大多数的表排序。因为目前我们不会做大量的表的排序,所以即使是最没有效率的排序方法,其执行速度都非常快。 通常的排序方法,是用表中的某一项和它的下一项作比较,如果大于的话,两项互相调换位置;所以,此方法是用第一项和第二项比较,第二项和第三项比较,一直比到表的最后而且适时地交换。在这个过程中一旦有交换的情形发生,那么就必须从第一项起再来一次;如果没有交换而能一直进行到表的结束,即表示排序成功。,例12.6 排序。用户最多可以输入30个名字,每个名字的长度最多可以为20个字符。当所有的名字输

24、入完成之后,程序将这些名字依递增的顺序排列好,然后在屏幕上显示,程序清单如下: ; filename:L126.ASM ; Page 60,132 Title nmsort(exe) sort names entered from terminal ; STACK SEGMENT PARA STACK STACK DW 32 DUP (?) STACK ENDS ; ,DATASG SEGMENT PARA DATA NAMEPAR LABEL BYTE MAXNLEN DB 21 ;输入名字的最大长度 NAMELEN DB ? ;实际输入名字的长度 NAMEFLD DB 21 DUP( )

25、;存放输入的名字 CRLF DB 13,10, $ ;回车换行 ENDADDR DW ? ;地址,MESSG1 DB NAME?, $ ;提示 NAMECTR DB 00 ;输入了几个名字 NAMETAB DB 30 DUP(20 DUP( ) ;名字表 NAMESAV DB 20 DUP(?),13,10, $ ;显示表 SWAPPED DB 00 DATASG ENDS ; CODESG SEGMENT PARA CODE,BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,ES:DATASG,SS:STACK PUSH DS SUB AX,AX PUSH

26、AX MOV AX,DATASG MOV DS,AX MOV ES,AX CLD LEA DI,NAMETAB,CALL Q10CLR ;清屏 CALL Q20CURS ;设置光标位置 A20LOOP: CALL B10READ ;接受输入的名字 CMP NAMELEN,00 ;结束输入 JZ A30 CMP NAMECTR,30 ;输入了30个名字吗? JE A30 ;是,则结束输入,CALL D10STOR ;将输入的名字传送到名字表 JMP A20LOOP ;循环、输入下一个名字 A30: CALL Q10CLR ;清屏 CALL Q20CURS ;设置光标位置 CMP NAMECTR,

27、01 ;输入的是一个名字吗? JBE A40 ;是结束输入 CALL G10SORT ;对名字表排序 CALL K10DISP ;显示排序的结果,A40: RET BEGIN ENDP ; 接受输入的名字 ; B10READ PROC MOV AH,09 LEA DX,MESSG1 INT 21H ;显示提示 MOV AH,0AH,LEA DX,NAMEPAR INT 21H ;键盘输入名字 MOV AH,09 LEA DX,CRLF INT 21H ;回车换行 MOV BH,00 ;名字后的字符置为空格 MOV BL,NAMELEN ;取得字符的长度 MOV CX,21 ;计算余下的长度,S

28、UB CX,BX B20: MOV NAMEFLDBX,20H ;余下的位置存放空格 INC BX LOOP B20 RET B10READ ENDP ; 输入的名字存入排序表 ; ,D10STOR PROC INC NAMECTR ;每输入一个名字加1 CLD ;字串指令增值 LEA SI,NAMEFLD ;输入名字的首地址 MOV CX,10 REP MOVSW ;传送名字到排序表 RET D10STOR ENDP,; 对名字排序 ; G10SORT PROC SUB DI,40 ;计算表的结束位置 MOV ENDADDR,DI G20: MOV SWAPPED,00 LEA SI,NAM

29、ETAB ;设置表的开始,G30: MOV CX,20 ;比较的长度 MOV DI,SI ADD DI,20 ;下一比较字符的位置 MOV AX,DI MOV BX,SI REPE CMPSB ;比较 JBE G40 ;小于、等于不交换 CALL H10XCHG ;反之交换,G40: MOV SI,AX CMP SI,ENDADDR ;表结束了吗? JBE G30 ;未结束循环 CMP SWAPPED,00 JNZ G20 RET G10SORT ENDP ; 排序交换,; H10XCHG PROC MOV CX,10 LEA DI,NAMESAV ;名字的暂存区 MOV SI,BX REP

30、MOVSW ;将较小的项保存 MOV CX,10 MOV DI,BX REP MOVSW ;传送较大的项到较低的单元,MOV CX,10 LEA SI,NAMESAV REP MOVSW ;传送保存的项到较高的单元 MOV SWAPPED,01 RET H10XCHG ENDP ; 显示排序的名字 ; ,K10DISP PROC LEA SI,NAMETAB ;表的首地址 K20: LEA DI,NAMESAV MOV CX,10 REP MOVSW MOV AH,09 LEA DX,NAMESAV INT 21H ;显示,DEC NAMECTR ;名字个数减1 JNZ K20 ;是最后一项吗

31、?不是循环,是返回系统 RET K10DISP ENDP ; Q10CLR PROC MOV AX,0600H MOV BH,07H,SUB CX,CX MOV DX,184FH INT 10H RET Q10CLR ENDP ; Q20CURS PROC MOV AH,02 SUB BH,BH,SUB DX,DX ;设置光标到0行0列 INT 10H RET Q20CURS ENDP ; CODESG ENDS END BEGIN,12.7 TYPE、LENGTH和SIZE运算符,汇编程序提供了一些很有用的运算符。例如,表的长度可能会经常性地修改、变动,所以就必须为了新的定义而去修改程序。但

32、是使用TYPE、LENGTH和SIZE运算符,就会使指令数目减少。 假设,下面是一个10个字(Word)的表的定义: TABLEX DW 10 DUP(?),可以用TYPE运算符确定它的类型,本例子是DW;用LENGTH运算符可确定DUP的个数,本例子是10;用SIZE运算符则可以计算出该表的字节数,本例子是10220,下面的例子说明这三个运算符的用法: MOV AX,TYPE TABLEX ;AX0002 MOV BX,LENGTH TABLEX ;BX000A(10) MOV CX,SIZE TABLEX ;CX0014(20),你可以利用LENGTH和SIZE所返回的值,决定何时该停止对表的搜寻和排序。如果SI寄存器在搜寻时地址是递增的,就可以用如下的指令去测试: CMP SI,SIZE TABLEX 在第17章“汇编程序伪指令参考资料”中,有对TYPE、LENGTH和SIZE运算符的详细介绍。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1