所以我编写的代码从用户那里获取一个字符串,其格式是第一个字符是非数字字符,其余字符是数字。我的代码删除了第一个字符并将剩余的数字存储在变量中。现在,我正在尝试向其余数字添加常量(示例5)并将其打印出来。我不确定什么是错的。
.data
string: .asciiz "Enter a string:\n"
string1: .asciiz "The value +5 is:\n"
inputString: .space 20
outInt: .word 0
int5: .word 5
addedInt: .word 0
.text
main:
#print initial string to console insruction 4
li $v0, 4
la $a0, string
syscall
#get first string from user
li $v0, 8
la $a0, inputString
li $a1, 8 #a1 contains max length of string to be entered
la $t0, ($a0)
syscall
addiu $t0, $t0, 1 #remove first letter
li $v0, 4 #prints out remaining numbers without leading character
la $a0, ($t0)
syscall
sw $a0, outInt #store new word in outInt
lw $t0, outInt #print out outInt to check if its correct
la $a0, ($t0)
syscall
lw $t1, int5
add $t2, $t0, $t1 #add 5 to the remaining numbers
sw $t2, addedInt #store result
li $v0, 4
la $a0, string1 #print the value + 5 string
syscall
li $v0, 1 #output a number (not a string)
lw $a0, addedInt
syscall
jr $ra
输入字符串“X123”时的输出是:
输入字符串:
X123
123
123
值+5是:
268501033
答案 0 :(得分:1)
您的代码的作用:
将字符串输入到地址inputString
的20字节内存缓冲区(在MARS下恰好是268501027
,看起来与运行期间的分配完全相同)。
如果用户输入" X123",那么内存中的字节如下所示:58 31 32 33 0A 00 00 00 ...
(没有找到,如何在MARS中显示每字节的内存,所以你必须了解little-endian是如何工作的,以及MARS中显示的那些字值如何分解为特定的单个字节),0x58是字母X的ASCII代码,0x31是字母/数字1的ASCII代码,等等... 0x0A是换行符(输入的一部分!),剩下的零是你的运气,MARS在代码运行开始时为你提供归零的.data段,所以你的下一个用户字符串输出正确地为零终止(并确实做到了)也换行。)
然后从地址inputString+1
输出字符串,该字符串指向数字0x31
的{{1}} = ASCII代码,然后是剩余的用户输入,因此是预期的(?)字符串" 123 \ n"输出。注意"删除第一个字母"不会从机器上移除任何东西,只需调整指针,然后将其用作" start"的字符串。真正删除相同内存空间中的字母将要求您将所有字母逐字节地复制到先前的地址,这是更昂贵的操作,然后将单个指针调整为一。
'1'
这会将调整后的地址sw $a0, outInt #store new word in outInt
存储到地址268501028
的内存中。它不存储单词本身。此处也没有将字符串转换为int。你要做的只是存储指针(内存地址),即32b无符号整数268501028。
然后你调用next outInt
而没有明确说明syscall
参数,所以重新使用前一个值v0
,再次从同一个地址输出字符串,所以你再次得到相同的输出4
。我建议始终在每个"123\n"
之前明确设置v0
,即使它与已经在寄存器中的值相同,也可以在头部调试时更容易地读取源代码。审查。
最后,您将值5加载到syscall
,并将其添加到该地址t1
,结果为整数268501028
,并将其存储到地址268501033
的内存中。然后打印出+5标签,然后将该值加载回addedInt
,然后将其打印出来。
您应该使用您使用的MARS / SPIM系列模拟器的内置调试器,单步执行指令,并观察寄存器值+内存内容,将其与我的描述进行比较,以完全掌握这些指令实际执行的操作
修正:
"太广泛",基本上你需要:
a)将用户字符串转换为整数值:逐字加载输入,直到到达换行符或零终止符,将数字字母转换为值a0
,然后计算临时总和,为{{1 },以(ASCII_code - '0') == digit_value
开头。在循环结束时,sum = sum*10 + digit_value
将包含值sum = 0
(来自字符串sum
)。然后,您可以将123
添加为整数(获取值"123"
),并使用5
输出它。
b)在字符串上添加值5,即找到换行符/零终止符的地址,然后返回1,你有最后一位数的地址(如果输入有效!你可能想通过比较来验证地址128
,如果地址有效,您还可以检查内容是否在syscall, v0=1
.. inputString
范围内,即内容是ASCII数字字母。然后循环:1)如果结果为'0' = 0x30
,则将5添加到当前字母2),然后字符串看起来像数字,您可以输出它(分支到输出,显示'9' = 0x39
地址)。 3)从中减去10(即<= '9'
,然后inputString+1
)4)将地址减1(向左移动一个位置)5)验证地址。 6)检查内容:如果不是数字,则用字母'7'+5 = 60 = '<'
覆盖它,然后跳转到60 - 10 = 50 = digit-letter '2'
地址的输出('1'
等有效输入等于'1'
},并且内存将包含已修改的字符串"X99"
),如果为数字,则向其中添加一个并跳转到步骤2) - 检查结果值是否为inputString
。
就是这样,那就是&#34;添加5&#34;当你不操作整数值,但是在内存中使用ASCII字母时。可能听起来很多工作,但实际上编写+调试可能比变体a)中的转换字符串到int更简单。
最终你应该尝试编写这两种变体,只是为了更好地理解汇编中基本数据类型的工作原理,以及&#34;字符串&#34;之间的区别。和整数值(以及字节和字值),以及内存寻址的工作原理。
答案 1 :(得分:0)
sw $t2, addedInt #store result
li $v0, 4
la $a0, string1 #print the value + 5 string
syscall
您正在使用la
加载string1的地址。您应该使用lw
加载单词本身以打印字符串本身。我没看过您对字符串的处理方式,但我只是在自己的项目中完成了此操作。
hth