MIPS汇编合并有序数组:循环异常、乱码及降序实现求助
问题修复与降序实现方案
一、打印无限循环&lw指令报错的根因与修复
核心问题
你的打印逻辑没有正确的终止条件,导致数组指针越界访问无效内存(lw $s0, 0($a2)的报错就是访问了未分配的内存地址),进而触发无限循环并输出乱码。常见的错误场景:
- 用数组元素的某个特定值(比如0)作为终止标志,但原数组可能包含该值
- 未正确计算合并后数组的总长度,循环计数器没有上限
修复步骤
- 提前计算合并后数组的总长度:将两个输入数组的长度相加,存入寄存器(比如
$s3),作为循环终止的判断依据。 - 修正打印循环逻辑:用计数器和总长度比较,而非依赖元素值。示例代码片段:
# 假设合并后的升序数组基地址存在$a2,总长度存在$s3 move $t0, $zero # 初始化计数器为0 print_loop: bge $t0, $s3, end_print # 计数器 >= 总长度时退出循环 lw $s0, 0($a2) # 读取当前元素(此时$a2不会越界) # 打印元素的代码(调用syscall打印整数) li $v0, 1 move $a0, $s0 syscall # 打印分隔符(逗号) li $v0, 11 li $a0, ',' syscall addi $a2, $a2, 4 # 指针移动到下一个整数 addi $t0, $t0, 1 # 计数器自增 j print_loop end_print:
二、降序输出的实现方案
有两种简单可行的实现方式:
方式1:反转升序数组
在完成升序合并后,直接反转升序数组得到降序结果,适合逻辑简单的场景:
# 假设升序数组基地址为$a2,总长度为$s3 move $t0, $zero # 左指针(从数组头部开始) addi $t1, $s3, -1 # 右指针(从数组尾部开始) sll $t1, $t1, 2 # 转换为字节偏移(每个整数4字节) add $t1, $t1, $a2 reverse_loop: bge $t0, $t1, end_reverse # 左右指针相遇时停止 # 交换左右指针指向的元素 lw $t2, 0($t0) lw $t3, 0($t1) sw $t3, 0($t0) sw $t2, 0($t1) # 移动指针 addi $t0, $t0, 4 addi $t1, $t1, -4 j reverse_loop end_reverse: # 此时$a2指向的数组已变为降序,直接调用打印逻辑即可
方式2:双指针从尾部合并(直接生成降序数组)
如果不想依赖升序结果,可以直接用双指针从两个输入数组的末尾开始比较,将较大的元素放入新数组的末尾:
# 假设数组1基地址$a0,长度$s0;数组2基地址$a1,长度$s1 # 降序数组基地址$a2,总长度$s3 = $s0 + $s1 addi $t0, $s0, -1 # 数组1的尾部索引 addi $t1, $s1, -1 # 数组2的尾部索引 addi $t2, $s3, -1 # 降序数组的填充索引(从尾部开始) merge_desc_loop: blt $t0, $zero, copy_arr2 # 数组1已遍历完,复制数组2剩余元素 blt $t1, $zero, copy_arr1 # 数组2已遍历完,复制数组1剩余元素 # 计算两个数组当前尾部元素的地址 sll $t3, $t0, 2 add $t3, $t3, $a0 lw $t4, 0($t3) sll $t5, $t1, 2 add $t5, $t5, $a1 lw $t6, 0($t5) bgt $t4, $t6, take_arr1 # 数组1元素更大,取它 take_arr2: sll $t7, $t2, 2 add $t7, $t7, $a2 sw $t6, 0($t7) addi $t1, $t1, -1 j merge_next take_arr1: sll $t7, $t2, 2 add $t7, $t7, $a2 sw $t4, 0($t7) addi $t0, $t0, -1 merge_next: addi $t2, $t2, -1 j merge_desc_loop copy_arr2: blt $t1, $zero, end_merge_desc sll $t5, $t1, 2 add $t5, $t5, $a1 lw $t6, 0($t5) sll $t7, $t2, 2 add $t7, $t7, $a2 sw $t6, 0($t7) addi $t1, $t1, -1 addi $t2, $t2, -1 j copy_arr2 copy_arr1: blt $t0, $zero, end_merge_desc sll $t3, $t0, 2 add $t3, $t3, $a0 lw $t4, 0($t3) sll $t7, $t2, 2 add $t7, $t7, $a2 sw $t4, 0($t7) addi $t0, $t0, -1 addi $t2, $t2, -1 j copy_arr1 end_merge_desc: # 降序数组已生成,调用打印逻辑
三、额外注意事项
- 确保所有数组的内存空间提前分配足够(总长度*4字节),避免越界写入
- 打印分隔符时,注意最后一个元素后不要输出多余的逗号,可以在循环内判断是否是最后一个元素再打印分隔符
内容的提问来源于stack exchange,提问作者Miggy1133
相关产品推荐
相关产品推荐

