MIPS汇编电话簿项目:不同偏移读写数据异常排查求助
MIPS电话簿存储问题分析与排查建议
问题描述
大学MIPS汇编课程项目中,尝试通过内存不同偏移(0、20、40)存储电话簿条目,但加载打印特定偏移的字时,始终获取到最后一个偏移存储的值。
问题代码
Get_Entry: addi $sp,$sp,-4 sw $ra, 0($sp) la $a0,Telephone_base_address jal Get_Entry_Number move $a0,$v1 jal Get_Entry_Last_Name move $a0,$v1 jal Get_Entry_First_Name move $a0,$v1 jal Get_Entry_Phone_Number li $v0,4 lw $a0,0($v1) syscall lw $ra, 0($sp) ##restore $ra addi $sp, $sp, 4 jr $ra Get_Entry_Number: addi $sp,$sp,-4 sw $ra, 0($sp) move $t0,$a0 li $v0, 4 la $a0, get_entry_number syscall li $v0,12 syscall li $t1, 60 mul $t2,$t1,$v0 #addition of Telephone base address with the product add $t3,$t0,$t2 move $v1,$t3 lw $ra, 0($sp) ##restore $ra addi $sp, $sp, 4 jr $ra Get_Entry_Last_Name: addi $sp,$sp,-4 sw $ra, 0($sp) move $t0,$a0 li $v0, 4 la $a0, get_entry_last_name syscall li $v0, 8 # syscall code 8 for read_string la $a0,buffer # address of the buffer li $a1, 20 syscall sw $a0,0($t0) #sll $t0,$t0,20 move $v1,$t0 lw $ra, 0($sp) ##restore $ra addi $sp, $sp, 4 jr $ra Get_Entry_First_Name: addi $sp,$sp,-4 sw $ra, 0($sp) move $t0,$a0 li $v0, 4 la $a0, get_entry_first_name syscall li $v0, 8 # syscall code 8 for read_string la $a0,buffer # address of the buffer li $a1, 20 syscall sw $a0,20($t0) #sll $a0,$a0,20 move $v1,$t0 lw $ra, 0($sp) ##restore $ra addi $sp, $sp, 4 jr $ra Get_Entry_Phone_Number: addi $sp,$sp,-4 sw $ra, 0($sp) move $t0,$a0 li $v0, 4 la $a0, get_entry_phone_number syscall li $v0, 8 # syscall code 8 for read_string la $a0, buffer # address of the buffer li $a1, 20 syscall li $v0, 8 # syscall code 8 for read_string move $a0,$t0 # address of the buffer li $a1, 20 syscall move $v1,$t0 lw $ra, 0($sp) ##restore $ra addi $sp, $sp, 4 jr $ra
核心问题原因
- 输入数字未转ASCII码:
Get_Entry_Number中用syscall 12读取的是字符的ASCII值(比如输入'0'得到48),直接乘以60计算偏移会导致地址完全错误,后续所有条目都存在了错误的内存区域。 - 存储的是缓冲区地址而非字符串内容:
Get_Entry_Last_Name和Get_Entry_First_Name中,调用syscall 8把字符串读入buffer后,用sw $a0, offset($t0)存储的是buffer的地址,不是字符串本身。所有条目都指向同一个buffer,每次新输入都会覆盖buffer内容,打印时自然只会显示最后一次输入的内容。 - 电话号码读取逻辑冗余错误:
Get_Entry_Phone_Number中连续两次调用syscall 8,第二次直接把输入写入目标地址,不仅覆盖了之前的操作,还破坏了整个条目的存储结构。 - 打印时的地址引用错误:
Get_Entry中用lw $a0,0($v1)加载的是之前存储的buffer地址,而非目标偏移处的字符串内容,进一步导致打印结果始终指向被覆盖的buffer。
排查与修复建议
- 修正数字输入处理:在
Get_Entry_Number中,读取字符后将ASCII码转为数字,比如添加sub $v0, $v0, 48,确保输入'0'得到0、'1'得到1,再计算偏移量。 - 复制字符串内容而非存储地址:替换
sw $a0, offset($t0)为字符串复制逻辑,比如用循环将buffer中的每个字节逐个复制到目标偏移地址(注意包含终止符'\0')。 - 清理电话号码读取逻辑:删除
Get_Entry_Phone_Number中第一次冗余的syscall 8,直接将输入写入目标偏移(比如40($t0)),或者先读入buffer再复制到目标地址,保持和姓名存储逻辑一致。 - 验证内存地址正确性:使用调试工具(比如MARS的内存查看器)检查每个条目存储的地址和内容,确认偏移计算正确,字符串确实被写入了预期的内存位置。
- 调整打印逻辑:如果直接在目标地址存储字符串,打印时直接将目标偏移地址加载到
$a0即可,无需lw操作(比如la $a0, 0($v1)或者直接用move $a0, $v1)。
内容的提问来源于stack exchange,提问作者dannyph
相关产品推荐
相关产品推荐

