我需要帮助计算整数数组中所有元素的总和。我似乎无法正常工作。如果您不提出基于以下更改的解决方案,我将不胜感激;请勿更改或使用此行下方的任何内容">
预期结果:
11个整数之和为217
当前和不正确的结果:
11整数之和为11
代码片段:
##############################################################################
# DESCRIPTION: Calculates the total sum of all elements in an integer array
#
# INPUT: $a0 - The address of the first number in the array
# $a1 - Number of integers stored in the array
#
# OUTPUT: $v0 - The sum of all numbers in the integer array
##############################################################################
.text
j main
int_array_sum:
## Clues:
## - Do not forget to clear registers that do not have an edge content
## - An integer corresponds to 4 bytes of memory. Each integer is thus 32 bits
## - If you want to multiply the contents of a register with an even two-power,
## a common trick (hint) is to shift bits a few steps left.
## Example (verify with pen and paper. sll = Shift Left Logical):
## sll $t1, $t0, 2 # $t1 = $t0 * 4
## sll $t0, $t1, 4 # $t0 = $t1 * 16
#pseudocode:
# If $t0 (i) is = $a1 skip to end_int # Done if i == N
# Multiply $t0 by 4 and store it in $t1 # Indexadr = i * 4
# Add $t1 with $a0 and save in $t2 # Address = $a0 + Indexadr
# Retrieve the number from memory that $t2 points to and store in $t3 # n = A [i]
# Add $t3 to $v0 (results register) # Sum = Sum + n
# Add 1 to register $t0 # i = i + 1
# Skip to for_every_int
#### WRITE YOUR ASSEMBLY CODE HERE ####
li $v0, 0
li $t0, 0
loopA:
#If $t0 (i) is = $a1 skip to end_int
beq $t0, $a1, end_int # Done if i == N
# Multiply $t0 by 4 and store it in $t1
sll $t1, $t0, 2 # Indexadr = i * 4
#Add $t1 with $a0 and save in $t2
add $t2, $t1, $a0 # Address = $a0 + Indexadr
#Retrieve the number from memory that $t2 points to and store in $t3
lb $t3, 0($t2) # Load the number from array # n = A [i]
#Add $t3 to $v0 (results register)
addu $v0, $v0, $t3 # Sum = Sum + n
#Add 1 to register $t0
add $t0, $t0, 1 # i = i + 1
#Repeat
j loopA
end_int:
jr $ra # Return to calling code
##############################################################################
##############################################################################
##
## *** Don't change or use ANYTHING below this line.
##
##############################################################################
##############################################################################
### Data that is being used as main program
.data
INT_COUNT:
.word 11
INT_ARRAY:
.word 1, 3, 6, 9, 2, 4, 6, 8, 10, 55, 113
INT_1_str:
.asciiz "Sum of the "
INT_2_str:
.asciiz " integer is "
.text
.globl main
##############################################################################
#
# MAIN: Calls subroutine and prints the results
#
##############################################################################
main:
##---
### int_array_sum
##---
li $v0, 4
la $a0, INT_1_str
syscall # print string
lw $a0, INT_COUNT
li $v0, 1
syscall # print integer
li $v0, 4
la $a0, INT_2_str
syscall # print string
li $v0, -1
la $a0, INT_ARRAY
lw $a1, INT_COUNT
jal int_array_sum # run subroutine
# Print sum
add $a0, $v0, $zero
li $v0, 1
syscall # print integer (array sum)
###--- EXIT
li $v0, 10 # MARS / SPIM exit
syscall
#### EOF #####################################################################
好的,所以您已经修复了崩溃,并更新了关于最新问题的问题,即您不遵守参数和返回值的传递。
这改变了问题的性质,正如我所说,调试是一种交互式活动,不太适合StackOverflow。人们通常不赞成完全改变问题帖子的性质,以至于之前的答案不再相关。在这种情况下,最好发布一个新问题,而不是编辑现有问题。如果编辑现有问题可以使现有问题更加清晰,则可以对其进行编辑
尽管如此,重读作业顶部的注释/注释,其中指出输入参数在$a0
和$a1
中,输出返回值在$v0
:中
##############################################################################
# DESCRIPTION: Calculates the total sum of all elements in an integer array
#
# INPUT: $a0 - The address of the first number in the array
# $a1 - Number of integers stored in the array
#
# OUTPUT: $v0 - The sum of all numbers in the integer array
##############################################################################
这样做,而不是使用替代寄存器——也不为输入参数提供初始化器——这些输入参数由main
初始化,因为传递输入参数的全部思想就是由调用者提供值!
此外,让我们继续观察main
中紧邻函数调用的代码,并看到它提供了输入参数并查找输出返回值,如赋值的相同初始注释中所述。
li $v0, -1 # clearing answer register, let the sub provide proper value
la $a0, INT_ARRAY # passing first parameter
lw $a1, INT_COUNT # passing second parameter
jal int_array_sum # run subroutine
# Print sum
add $a0, $v0, $zero # expecting return value in $v0
li $v0, 1
syscall # print integer (array sum)
(现在,你为什么认为它认为总和是-1?)
好的,让我们从main
在上面做什么开始。首先,它清除(好吧,设置为-1)结果寄存器。
然后main
将INT_ARRAY的地址放入$a0
,将值11
放入$a1
——这是您的两个输入参数,因此您应该在函数中使用它们。
暂时停留在这个main
代码中,您会注意到,从函数调用返回时,这个代码期望函数的输出/返回值在$v0
中,但由于$v0
从main
清除到的-1没有修改,所以这就是打印的内容(您的代码未能在$v0
中返回正确的值。
好吧,现在考虑到main
是如何工作的(也根据输入/输出描述),函数的设置是INT_ARRAY指针在$a0
寄存器中——已经作为参数由main
传递——它在函数的最顶部,甚至在函数的第一行函数代码之前,就有这个正确的值。
好的,所以每当需要数组指针时,使用$a0
而不是$t0
--,并注意它已经预先初始化,所以只需使用,而无需通过某些la
指令进行任何进一步的启动
此外,您需要用于输出/返回值的寄存器是$v0
,因此每当您需要引用和变量时,请使用$v0
而不是$t3
,当您返回到调用者时,和值将在调用者期望的$v0
中。
接下来,用寄存器$a1
替换常数值11
;这是保存main
提供给您的长度参数的寄存器。
如果你要学习汇编语言,基本的调试技能应该在你的技能集中。
通过StackOverflow调试程序是一项挑战——调试是一项交互式活动,而StackOverload并不能真正满足这种形式!
因此,以下是一些思考过程。
您可以向前调试到错误或意外结果,也可以从错误或意外的结果向后调试。
当第一次运行新代码时,我更喜欢继续。单步执行并检查每条指令是否符合您的预期。如果任何一条指令所做的事情与你预期的不同,那么这就是重点。当寻找与预期的差异时,既要考虑指令的寄存器效应,也要考虑内存效应,然后,观察预期的控制流正在发生。
回过头来看,我们可能会问:0x00400088处的指令是什么?为什么访问位置0x10400000
?要回答这个问题,你必须向后看是什么指令创建了这个内存地址,然后确定为什么会出错,以及需要什么。
向前看通常比向后看更容易,尤其是对于有潜在拼写错误的新代码,如果你有多个错误,处理第一个错误的工作量比处理最后一个要少——最后一个错误可能无法处理复杂的早期错误/拼写错误,而向前看,除非你错过了什么,否则不会有错误的复合。
有时,编写一个更简单的程序并将这些简单的部分放在一起比编写一个完整的程序并对其进行调试更容易。因此,尝试将整个程序分解为更小的部分,并使每个更小的部分发挥作用,然后将这些较小的解决方案放在一起,形成一个更大的整体。
如果你在循环方面遇到困难,你可以从最简单的循环程序开始,如果你在这方面遇到问题,那么你可能会问一个关于你遇到问题的指令的技术问题。