如何在MIPS汇编中声明以N个整数数组为参数的函数
实现支持任意N个整数的MIPS动态数组
你当前的代码已经能完成固定大小数组的读写和打印,但要支持任意数量的整数,核心问题是静态数组的空间是预先分配好的,无法根据用户输入的N动态调整。解决这个问题的关键是使用MIPS的堆内存动态分配功能(通过syscall 9即sbrk指令)。
原代码各模块展示
原数据段(静态数组)
.data arr: .space 32 # 预留8个整数的空间(每个整数4字节) msg: .asciiz "Enter the number of elements to store: " msg1: .asciiz "Enter an integer value: "
原主程序
.text main: # 打印提示信息 la $a0, msg li $v0, 4 syscall # 读取元素个数 li $v0, 5 syscall move $s2,$v0 move $a1,$v0 # 将元素个数存入$a1 # 加载静态数组地址 la $a0, arr # 调用数组读取函数 jal read_array_function move $a0,$v0 # 将返回的数组地址传给打印函数 move $a1,$s2 jal print_array_function jal read_array_function # 结束程序 li $v0, 10 syscall
原数组读取函数
read_array_function: sub $sp, $sp, 24 # 分配栈空间 sw $a0, 0($sp) # 保存数组地址到栈 sw $a1, 4($sp) # 保存元素个数到栈 sw $ra, 8($sp) # 保存返回地址到栈 sw $zero, 12($sp) # 初始化循环计数器 sw $a0, 16($sp) # 保存数组起始地址用于返回 lw $t0, 0($sp) # 从栈加载数组地址 lw $t1, 4($sp) # 从栈加载元素个数 lw $t2, 12($sp) # 从栈加载循环计数器 lw $t3, 8($sp) # 从栈加载返回地址 lw $t4, 16($sp) # 从栈加载数组起始地址 read_loop: beq $t2, $t1, end_read # 计数器等于元素个数时退出循环 la $a0,msg1 li $v0,4 syscall # 读取用户输入的整数 li $v0, 5 syscall # 将输入存入数组 sw $v0, ($t0) # 存储到当前数组地址 addi $t0, $t0, 4 # 移动到下一个元素地址 addi $t2, $t2, 1 # 递增计数器 j read_loop # 循环 end_read: lw $ra, 0($sp) # 恢复返回地址 addi $sp, $sp, 24 # 恢复栈指针 move $v0,$t4 jr $t3 # 返回调用者
原数组打印函数
print_array_function: sub $sp,$sp,12 # 分配12字节栈空间 sw $a0,0($sp) # 保存数组地址到栈 sw $zero,4($sp) # 初始化循环计数器为0 sw $a1,8($sp) # 保存元素个数到栈 lw $t0,0($sp) # 加载数组地址到$t0 lw $t1,4($sp) # 加载循环计数器到$t1 lw $t2,8($sp) # 加载元素个数到$t2 print_loop: beq $t1,$t2,end_print lw $a0,($t0) # 加载当前数组元素 li $v0,1 syscall addi $t0,$t0,4 # 移动到下一个元素地址 addi $t1,$t1,1 # 递增计数器 j print_loop end_print: addi $sp, $sp, 12 # 恢复栈指针 jr $ra # 返回调用者
修改为支持任意N个整数的方案
核心修改点:动态分配堆内存
MIPS中可以通过syscall 9(sbrk)向操作系统申请堆内存,根据用户输入的N计算需要的内存大小(每个整数占4字节,所以总大小是N * 4),用这个大小调用sbrk后,$v0会返回分配到的内存起始地址,用这个地址作为数组的基地址即可。
修改后的完整代码
数据段(移除静态数组)
.data # arr: .space 32 # 不再使用静态数组,改用动态分配 msg: .asciiz "Enter the number of elements to store: " msg1: .asciiz "Enter an integer value: "
主程序(新增动态内存分配逻辑)
.text main: # 提示输入元素个数 la $a0, msg li $v0, 4 syscall # 读取元素个数N li $v0, 5 syscall move $s2, $v0 # 保存N到$s2 move $a1, $v0 # 将N存入$a1 # 计算所需内存大小:N * 4字节 mul $a0, $s2, 4 li $v0, 9 # syscall 9: sbrk,申请堆内存 syscall move $a0, $v0 # $a0现在是动态数组的起始地址 # 调用数组读取函数 jal read_array_function move $a0, $v0 # 将数组地址传给打印函数 move $a1, $s2 jal print_array_function # 可选:释放堆内存(模拟器中通常不需要,若需释放可执行以下代码) # mul $a0, $s2, -4 # li $v0, 9 # syscall # 结束程序 li $v0, 10 syscall
优化后的数组读取函数(简化栈操作)
原读取函数的栈操作有冗余,可简化为:
read_array_function: sub $sp, $sp, 16 # 仅分配必要的栈空间(保存$a0, $a1, $ra, 计数器) sw $a0, 0($sp) # 保存数组起始地址 sw $a1, 4($sp) # 保存元素个数 sw $ra, 8($sp) # 保存返回地址 sw $zero, 12($sp) # 初始化循环计数器 lw $t0, 0($sp) # 当前数组地址 lw $t1, 4($sp) # 元素个数 lw $t2, 12($sp) # 循环计数器 read_loop: beq $t2, $t1, end_read la $a0, msg1 li $v0, 4 syscall li $v0, 5 syscall sw $v0, ($t0) addi $t0, $t0, 4 addi $t2, $t2, 1 j read_loop end_read: lw $ra, 8($sp) lw $v0, 0($sp) # 返回数组起始地址 addi $sp, $sp, 16 jr $ra
数组打印函数无需修改
原打印函数是基于传入的数组地址和元素个数操作的,和数组的存储位置(静态/动态)无关,所以可以直接沿用。
说明
通过动态分配堆内存,程序可以根据用户输入的N灵活分配对应大小的空间,彻底解决静态数组大小固定的限制。需要注意的是,在MIPS模拟器(比如SPIM、MARS)中,堆内存的管理相对宽松,通常不需要手动释放,但在实际系统中,动态分配的内存使用完后应该释放避免内存泄漏。
内容的提问来源于stack exchange,提问作者Utku Berki
相关产品推荐
相关产品推荐

