# 实验四:循环程序设计 ## 一、实验目的 1. 掌握循环程序的基本结构和设计方法 2. 理解LOOP指令的工作原理和使用方法 3. 掌握多重循环程序的设计技术 4. 理解循环计数器的作用和设置方法 --- ## 二、基础性实验 ### 实验4_1 循环结构一:求累加和 #### 实验目的 掌握利用LOOP指令实现循环程序的设计方法。 #### 实验内容 利用循环程序求1+2+3+...+10的和。 #### 程序代码 ```asm DATAS SEGMENT LIST DB 01H,02H,03H,04H,05H,06H,07H,08H,09H,0AH COUNT EQU 10 RESULT DB ? DATAS ENDS CODES SEGMENT ASSUME CS:CODES, DS:DATAS START: MOV AX, DATAS MOV DS, AX LEA SI, LIST ; SI指向数据表首地址 MOV CX, COUNT ; 设置循环计数初值 XOR BL, BL ; BL清0,累加和初值为0 XOR BH, BH ; BH清0 L1: MOV AL, [SI] ; 取出数据 ADD BL, AL ; 累加到BL INC SI ; SI指向下一个数据 LOOP L1 ; CX!=0,继续循环 MOV RESULT, BL ; 保存结果 MOV AH, 4CH INT 21H CODES ENDS END START ``` #### 程序分析 1. **数据段定义**: - `LIST DB 01H,02H,03H,04H,05H,06H,07H,08H,09H,0AH` 定义了一个数据表,包含10个数据:01H,02H,...,0AH(即1,2,...,10) - `COUNT EQU 10` 定义了数据个数为10 - `RESULT DB ?` 用于存储累加结果 2. **循环结构**: - 使用SI作为指针(变址寄存器),通过 `LEA SI, LIST` 初始化为数据表首地址 - 使用CX作为循环计数器,初值为10 - 使用BL寄存器存储累加和,初值为0 3. **指令说明**: - `MOV AL, [SI]`:从内存读取数据到AL - `ADD BL, AL`:将AL中的数据累加到BL - `INC SI`:SI指向下一个数据 - `LOOP L1`:CX自动减1,如果CX≠0则跳转到L1继续循环 4. **累加结果**: - 1+2+3+...+10 = 55 = 37H - 结果存储在BL中,即RESULT单元 #### 验证结果 运行程序后,RESULT中保存累加和37H(55)。 --- ## 三、加强性实验 ### 实验4_2 循环结构二:多重循环求累加和 #### 实验目的 掌握多重循环程序的设计方法,理解内嵌循环的汇编实现。 #### 实验内容 利用二重循环求累加和,体会外层循环和内层循环的配合。 #### 程序代码 ```asm DATAS SEGMENT LIST DB 01H,02H,03H,04H,05H,06H,07H,08H,09H,0AH COUNT EQU 10 RESULT DB ? DATAS ENDS CODES SEGMENT ASSUME CS:CODES, DS:DATAS START: MOV AX, DATAS MOV DS, AX LEA SI, LIST ; SI指向数据表首地址 MOV CX, COUNT ; 外层循环计数 XOR BL, BL ; BL清0,累加和初值为0 L1: PUSH CX ; 保存外层循环计数 MOV CX, COUNT ; 内层循环计数 XOR BH, BH ; BH清0 L2: MOV AL, [SI] ; 取出数据 ADD BH, AL ; 内层累加到BH INC SI ; SI指向下一个数据 LOOP L2 ; 内层循环 POP CX ; 恢复外层循环计数 ADD BL, BH ; 外层累加 LOOP L1 ; 外层循环 MOV RESULT, BL ; 保存结果 MOV AH, 4CH INT 21H CODES ENDS END START ``` #### 程序分析 1. **二重循环结构**: - **外层循环(L1)**:控制内层循环的执行次数 - **内层循环(L2)**:完成每次内层循环的累加操作 2. **寄存器保护**: - `PUSH CX`:在进入内层循环前保存外层循环计数器的值 - `POP CX`:在内层循环结束后恢复外层循环计数器的值 - 这是多重循环中保护外层计数器的重要技巧 3. **执行流程**: - 外层循环第1次:内层循环累加10个数到BH,然后BL+=BH - 外层循环第2次:内层循环再次累加10个数到BH,然后BL+=BH - 重复上述过程,直到外层循环结束 4. **累加原理**: - 内层循环将10个数据累加到BH - 外层循环将每次内层循环的BH结果累加到BL - 最终结果仍然是所有数据的总和(55=37H) 5. **注意问题**: - 8位寄存器(BL、BH)最大只能存储255,累加和不应超过这个范围 - 本例中10个数的累加和为55,小于255,结果正确 #### 验证结果 运行程序后,RESULT中保存最终的累加和37H(55),与实验4_1结果相同。 --- ## 四、实验步骤 ### 4.1 单重循环程序实验步骤 1. **编辑源程序**:在编辑器中输入实验4_1的源代码,保存为 `实验4_1_循环结构一.asm` 2. **汇编连接**: ``` MASM 实验4_1_循环结构一.asm; LINK 实验4_1_循环结构一.obj; ``` 3. **运行程序**: ``` 实验4_1_循环结构一.exe ``` 4. **调试观察**: - 在DEBUG中加载程序:`DEBUG 实验4_1_循环结构一.exe` - 使用 `T` 命令单步执行,观察CX的变化 - 使用 `R` 命令查看寄存器状态 - 使用 `D` 命令查看RESULT单元的内容 ### 4.2 多重循环程序实验步骤 1. **编辑源程序**:在编辑器中输入实验4_2的源代码,保存为 `实验4_2_循环结构二.asm` 2. **汇编连接**: ``` MASM 实验4_2_循环结构二.asm; LINK 实验4_2_循环结构二.obj; ``` 3. **运行程序**: ``` 实验4_2_循环结构二.exe ``` 4. **调试观察**: - 在DEBUG中观察PUSH/POP对栈的影响 - 跟踪内层循环L2和外层循环L1的执行 - 验证BH和BL的变化过程 --- ## 五、思考题 ### 5.1 LOOP指令的工作原理是什么? LOOP指令是8086汇编语言中实现循环的基本指令,它完成以下操作: 1. 将CX寄存器减1 2. 如果CX≠0,则跳转到指定的标号处继续执行 3. 如果CX=0,则继续执行下一条指令(循环结束) LOOP指令相当于以下两条指令的组合: ``` DEC CX JNZ label ``` ### 5.2 循环程序设计中需要注意哪些问题? 1. **循环计数器的初始化**:在循环开始前必须给CX设置正确的初值 2. **循环条件的设置**:确保循环能够正确终止,避免死循环 3. **寄存器的保护**:在多重循环中,需要保护外层循环的计数器,使用PUSH/POP指令 4. **数据指针的更新**:如果使用指针访问数据,必须正确更新指针(如INC SI) 5. **寄存器的选择**:根据数据范围选择合适的寄存器宽度,避免溢出 ### 5.3 多重循环中为什么要保护外层循环计数器? 在多重循环中,内层循环也会使用CX作为计数器。如果不保护外层循环的CX值,当内层循环结束时,CX会被内层循环修改为0,导致外层循环无法正确继续。 通过PUSH指令在进入内层循环前保存CX的值,内层循环结束后用POP指令恢复,这样外层循环就能继续正确执行。 ### 5.4 单重循环和多重循环有何区别? 1. **结构复杂度**: - 单重循环:只有一层循环结构 - 多重循环:有多层循环嵌套,外层循环包含内层循环 2. **计数器使用**: - 单重循环:CX在整个循环过程中只需要一个值 - 多重循环:需要保护外层循环计数器,内层循环可以复用CX 3. **应用场景**: - 单重循环:处理简单的重复操作,如累加一个数组 - 多重循环:处理矩阵运算、多维数组遍历等复杂问题 --- ## 六、实验总结 1. **循环程序的基本结构**:初始化循环计数器 → 循环体 → 更新循环条件 → LOOP指令跳转 2. **LOOP指令的理解**:LOOP指令自动完成CX减1和条件判断跳转,是实现循环的关键指令 3. **单重循环的应用**:适用于处理线性结构的数据,如数组求和、数据查找等 4. **多重循环的设计要点**: - 外层循环控制执行次数 - 内层循环完成具体操作 - 使用PUSH/POP保护外层计数器 - 注意内外层循环的配合 5. **循环程序调试技巧**: - 观察CX的变化,确认循环次数正确 - 检查指针更新,确保数据访问正确 - 注意寄存器的值,避免溢出 6. **循环程序设计的优势**:使用循环结构可以大大减少重复代码,提高程序的可读性和效率