实现数独已解单元格计数函数遇溢出及地址错误求助
数独已解单元格计数函数的溢出与地址错误分析
问题根源
你的代码存在几个致命错误,直接导致了算术溢出警告和"Bad address in data/stack"错误:
无视传入参数,硬编码全局board地址:
函数设计要求通过$a0传入棋盘指针,但你用la $s0, board直接加载全局变量地址,完全跳过了传入参数。如果调用时传入的地址和全局board不匹配,或者全局board的内存区域无法正常访问,必然触发地址错误。寄存器被子函数覆盖,逻辑彻底混乱:
你把计数器存在$v0中,但jal is_cell_solved调用后,子函数的返回值会直接覆盖$v0。之后执行的addi $v0, $v0, 1根本不是在递增原计数器,而是基于子函数的返回值做修改,这不仅会导致计数完全错误,还可能因为子函数返回异常值引发算术溢出。违反MIPS寄存器调用约定:
$s0属于被调用者保存寄存器,你的函数直接使用它却没有先保存到栈中,会破坏调用者的寄存器状态,进而引发栈或数据地址的混乱。计数逻辑完全不符合需求:
不管单元格是否已解都强制加1,完全违背了"统计已解单元格数量"的要求,属于核心功能逻辑错误。
修正方案与代码示例
按照MIPS调用约定和功能需求,修正后的代码如下:
# a0: pointer to board # v0: number of solved cells count_solved_cells: addi $sp, $sp, -12 # 为保存寄存器分配栈空间($s0, $s1, $ra) sw $s0, 0($sp) sw $s1, 4($sp) sw $ra, 8($sp) li $s1, 0 # 用$s1存计数器,避免被子函数覆盖$v0 move $s0, $a0 # 把传入的棋盘指针保存到$s0 li $t0, 81 # 循环计数器:共81个单元格 count_cells_loop: move $a0, $s0 # 将当前单元格地址传入子函数的参数寄存器$a0 jal is_cell_solved # 调用判断函数,$v0返回1(已解)/0(未解) add $s1, $s1, $v0 # 仅当单元格已解时,计数器加1 addi $s0, $s0, 10 # 移动到下一个单元格(每个占10字节) addi $t0, $t0, -1 # 循环次数减1 bnez $t0, count_cells_loop # 未遍历完则继续循环 move $v0, $s1 # 将最终计数赋值给返回寄存器$v0 lw $ra, 8($sp) # 恢复栈中保存的寄存器 lw $s1, 4($sp) lw $s0, 0($sp) addi $sp, $sp, 12 # 恢复栈指针 jr $ra
额外检查项
- 确认
is_cell_solved函数的返回值符合预期:必须返回1表示已解,0表示未解,且绝对不能修改传入的单元格数据(满足"不修改棋盘状态"的要求)。 - 如果仍有溢出警告,检查
is_cell_solved是否返回了非0/1的异常值(比如错误返回了单元格数值而非状态)。 - 验证传入的棋盘指针指向的内存块大小:确保至少有810字节的可读取内存,避免越界访问引发地址错误。
内容的提问来源于stack exchange,提问作者nanobot101
相关产品推荐
相关产品推荐

