【问题标题】:MIPS, dynamic array, third input overwrites the secondMIPS,动态数组,第三个输入覆盖第二个
【发布时间】:2016-09-26 21:59:11
【问题描述】:

我正在尝试创建一个数组,该数组包含任意数量的个位数整数,当用户输入 -1 时,它会停止取更多。但是,第一个和第二个数字被正确存储。一旦我对第三个输入进行系统调用,存储我的第二个数字的内存地址就会被覆盖。这是我在 MIPS 中的代码。

    # switch to the Data segment
    .data
# global data is defined here

myArray:
    .word 256
char: 
    .word 4
sp:
    .asciiz " "
cr:
    .asciiz "\n"
error_string:
    .asciiz "\ONE DOES NOT SIMPLY WALK INTO MORDOR."
array_input:
    .asciiz "\Please type a digit. Press enter after each. End array with -1 input.\n"
neg_one:
    .asciiz "\1-"

 # switch to the Text segment
    .text
    .globl  main
main:
    # the rest of the main program goes here
    lui $s7, 0x000a  # set first half of $s7
    ori $s7, $s7, 0x312d # set $s7 to compare with beq and exit input, $s7 = -1 now.
    addi $t3, $t3, 0 # set counter for decrementing array later
    la $s1, myArray # set base address of array to $s1
    la $a0, array_input
    jal Print_string


input_loop:
    la $a0, char
    li $a1, 4
    jal Input # prompt user for digit input

    lb $t1, char
    lw $t2, char # store char from buffer into t1 (does this strip newline?)
    beq $t2, $s7, begin_sort # branch if input is equivalent to -1


    blt $t1, 48, error      # check if char is not a digit (ascii<'0')
    bgt $t1, 57, error      # check if char is not a digit (ascii>'9')
    addi $t1, $t1, -48


    sw $t1, 0($s1) # store char into array

    move $a0, $t1
    jal Print_integer # print number that was input
    la $a0, cr
    jal Print_string # print newline char

    addi $s1, $s1, 4 # increment array address
    addi $t3, $t3, 1 # increment array counter
    j input_loop # jump back up when -1 not entered

begin_sort:
    Jal Exit

.globl Input
Input: # gets a string from user into register
    addi $v0, $zero, 8
    syscall #calls for input
    jr $ra

    .globl Print_integer
Print_integer: # print the integer in register a0. Loading one into $v0 from addi makes syscall print
    addi $v0, $zero, 1
    syscall
    jr $ra

    .globl Print_string
Print_string: # print the string whose starting address is in register a0
    addi $v0, $zero, 4
    syscall 
    jr $ra

    .globl Exit
Exit: # end the program, no explicit return status
    addi $v0, $zero, 10
    syscall
    jr $ra

例如,我输入 8,然后是 5,然后是 3,对于我的数组地址 0x10010000,值 (+0) 是 0x08,值 (+4) 是 0x0a,值 (+8) 是 0x03。显然 (+4) 是错误的,应该只是 0x05。在 Jal Input 进行 Syscall 之前一直是这样。所以我认为我在 char 的地址有问题?在此之后我无法输入单个数字,因为我的代码开始变得时髦。我也知道我可以使用 sb,但我相信我现在需要存储这些 4 个字节以供以后操作。本质上,是什么在值(+4)处覆盖了我的内存地址?非常感谢您在这里的任何输入。

【问题讨论】:

    标签: mips dynamic-arrays


    【解决方案1】:

    解决方案?:哇,我通过将 myArray 和 char 部分移动到字符串声明下方(如 sp 和 cr)来解决了这个问题。我认为这是因为数组空间应该在字符串之后声明,否则字符串将覆盖您刚刚声明的任何空间。然后,当我调整我的动态数组时,我破坏了存储的字符串。奇怪的东西。我仍然希望得到更完整的解释。

    【讨论】:

    • 很抱歉,但这确实不是对错误的修复。请参阅我的回答,了解原因。
    【解决方案2】:

    您错误地使用了.word 指令:

    myArray:    .word       256
    

    定义了一个包含 256 个元素的数组。它定义了一个初始值为256的标量字。数组的大小只有 4个字节。

    因此,在第一次存储到数组之后,您正在写到末尾(即 C 语言中的 未定义行为)。

    在您的回答中,您将myArray 移至.data 部分的末尾。但是,这不是修复。它只是“掩盖”问题。而且,如果你有订单myArray | char,那么myArray的第二个元素将包含垃圾数据。

    定义数组的正确方法是使用.space 指令。它保留给定数量的字节。所以,myArray 的正确定义是:

    myArray:    .space      1024
    

    char 数组也有类似的问题,但你“走运了”。

    还有一些错误。特别是“-1”检查很弱,如果它起作用的话。

    我已经创建了您的程序的三个版本。带有错误注释的版本。一个被清理和修复的第二个。第三个更简单、更通用、更高效,因为它使用不同的syscall 来获取用户输入。


    这里是带注释的版本[请原谅无偿的风格清理]:

    # switch to the Data segment
        .data
        # global data is defined here
    
        # NOTE/BUG: this defines a _single_ 32 bit word [with initial value of 256]
        # and _not_ an array with 256 elements
        # as it is, myArray is only 4 bytes long
    myArray:    .word       256
    
        # NOTE/BUG: this has similar problems to above but you luck out because
        # it defines an area of length 4 by virtue of the .word directive and _not_
        # the 4
    char:       .word       4
    
    sp:         .asciiz     " "
    cr:         .asciiz     "\n"
    error_string:   .asciiz "\ONE DOES NOT SIMPLY WALK INTO MORDOR."
    array_input:    .asciiz "\Please type a digit. Press enter after each. End array with -1 input.\n"
    
        # NOTE/BUG: this string is incorrect for its intended use below
        # NOTE/BUG: this isn't used
    neg_one:    .asciiz     "\1-"
    
    # switch to the Text segment
        .text
        .globl  main
    
        # the rest of the main program goes here
    main:
        # NOTE/BUG: this is a poor way to initialize this. use "li" or "lw" instead
        # but also see below
        # NOTE/BUG: manually compensating for little endian is tedious
        lui     $s7,0x000a              # set first half of $s7
        ori     $s7,$s7,0x312d          # set $s7 to compare with beq and exit input, $s7 = -1 now.
    
        # NOTE/BUG: this has _no_ effect
        addi    $t3,$t3,0               # set counter for decrementing array later
    
        la      $s1,myArray             # set base address of array to $s1
    
        # NOTE/BUG: although not a bug, this should be part of the loop
        la      $a0,array_input
        jal     Print_string
    
    input_loop:
        la      $a0,char
        li      $a1,4
        jal     Input                   # prompt user for digit input
    
        lb      $t1,char
    
        # NOTE/BUG: this is a weak way to check for -1
        lw      $t2,char                # store char from buffer into t1 (does this strip newline?)
        beq     $t2,$s7,begin_sort      # branch if input is equivalent to -1
    
        blt     $t1,48,error            # check if char is not a digit (ascii<'0')
        bgt     $t1,57,error            # check if char is not a digit (ascii>'9')
        addi    $t1,$t1,-48
    
        sw      $t1,0($s1)              # store char into array
    
        move    $a0,$t1
        jal     Print_integer           # print number that was input
    
        la      $a0,cr
        jal     Print_string            # print newline char
    
        addi    $s1,$s1,4               # increment array address
        addi    $t3,$t3,1               # increment array counter
        j       input_loop              # jump back up when -1 not entered
    
    begin_sort:
        # NOTE/BUG: this _must_ be "jal" and _not_ "Jal"
        # NOTE/BUG: this should just be "j" or just move the "Exit" code here
        Jal     Exit
    
    error:
        la      $a0,error_string
        li      $v0,4
        syscall
        j       input_loop
    
        .globl  Input
    # gets a string from user into register
    Input:
        addi    $v0,$zero,8
        syscall                         # calls for input
        jr      $ra
    
        .globl  Print_integer
    # print the integer in register a0. Loading one into $v0 from addi makes syscall print
    Print_integer:
        addi    $v0,$zero,1
        syscall
        jr      $ra
    
        .globl  Print_string
    # print the string whose starting address is in register a0
    Print_string:
        addi    $v0,$zero,4
        syscall
        jr      $ra
    
        .globl  Exit
    # end the program, no explicit return status
    Exit:
        addi    $v0,$zero,10
        syscall
        jr      $ra
    

    这是清理后的工作版本。请注意,进行“-1”检查的最佳方法是去除换行符并实现strcmp 函数,但我做了一些更简单的事情

    # switch to the Data segment
        .data
        # global data is defined here
    
    myArray:    .space      1024
    eArray:
    
    char:       .space      80
    echar:
    
    sp:         .asciiz     " "
    cr:         .asciiz     "\n"
    error_string:   .asciiz "\ONE DOES NOT SIMPLY WALK INTO MORDOR."
    array_input:    .asciiz "\Please type a digit. Press enter after each. End array with -1 input.\n"
    
    # switch to the Text segment
        .text
        .globl  main
    
        # the rest of the main program goes here
    main:
        la      $s1,myArray             # set base address of array to $s1
        la      $s2,eArray              # get end of array
    
    input_loop:
        # prompt user
        la      $a0,array_input
        jal     Print_string
    
        # read in user's response
        # NOTE: unless you are _required_ to decode the number yourself, using
        # syscall 5 (read integer) is _much_ simpler
        la      $a0,char
        la      $a1,echar
        subu    $a1,$a1,$a0
        jal     Input                   # prompt user for digit input
    
        # check for -1 on input
        lb      $t2,0($a0)              # is first char "-"?
        bne     $t2,0x2D,not_negone     # no, fly
        lb      $t2,1($a0)              # is second char "1"?
        bne     $t2,0x31,not_negone     # no, fly
        lb      $t2,2($a0)              # is third char "\n"?
        beq     $t2,0x0A,begin_sort     # yes, fly
    
    not_negone:
        lb      $t1,0($a0)
        blt     $t1,48,error            # check if char is not a digit (ascii<'0')
        bgt     $t1,57,error            # check if char is not a digit (ascii>'9')
        addi    $t1,$t1,-48
    
        sw      $t1,0($s1)              # store char into array
    
        move    $a0,$t1
        jal     Print_integer           # print number that was input
    
        la      $a0,cr
        jal     Print_string            # print newline char
    
        addi    $s1,$s1,4               # increment array address -- over edge?
        blt     $s1,$s2,input_loop      # no, loop
    
    begin_sort:
        j       Exit
    
    error:
        la      $a0,error_string
        li      $v0,4
        syscall
        j       input_loop
    
    # gets a string from user into register
    Input:
        li      $v0,8
        syscall                         # calls for input
        jr      $ra
    
    # print the integer in register a0. Loading one into $v0 from addi makes syscall print
    Print_integer:
        li      $v0,1
        syscall
        jr      $ra
    
    # print the string whose starting address is in register a0
    Print_string:
        li      $v0,4
        syscall
        jr      $ra
    
    # end the program, no explicit return status
    Exit:
        li      $v0,10
        syscall
    

    上述程序仍然存在一个限制,即输入的数字只能是个位数。一般的解决方案是实现 atoi 的等价物。

    但是,如果您不需要进行自己的数字解析,使用 syscall #5 [读取整数] 会简单得多,允许任何整数,并且是大多数 mips 程序使用的.

    # switch to the Data segment
        .data
        # global data is defined here
    
    myArray:    .space      1024
    eArray:
    
    sp:         .asciiz     " "
    cr:         .asciiz     "\n"
    error_string:   .asciiz "\ONE DOES NOT SIMPLY WALK INTO MORDOR."
    array_input:    .asciiz "\Please type a number. Press enter after each. End array with -1 input.\n"
    
    # switch to the Text segment
        .text
        .globl  main
    
        # the rest of the main program goes here
    main:
        la      $s1,myArray             # set base address of array to $s1
        la      $s2,eArray              # get end of array
    
    input_loop:
        # prompt user
        la      $a0,array_input
        jal     Print_string
    
        # read in user's response
        li      $v0,5
        syscall
        move    $t1,$v0
    
        # check for -1 on input
        bltz    $t1,begin_sort
    
        sw      $t1,0($s1)              # store char into array
    
        move    $a0,$t1
        jal     Print_integer           # print number that was input
    
        la      $a0,cr
        jal     Print_string            # print newline char
    
        addi    $s1,$s1,4               # increment array address -- over edge?
        blt     $s1,$s2,input_loop      # no, loop
    
    begin_sort:
        j       Exit
    
    error:
        la      $a0,error_string
        li      $v0,4
        syscall
        j       input_loop
    
    # gets a string from user into register
    Input:
        li      $v0,8
        syscall                         # calls for input
        jr      $ra
    
    # print the integer in register a0. Loading one into $v0 from addi makes syscall print
    Print_integer:
        li      $v0,1
        syscall
        jr      $ra
    
    # print the string whose starting address is in register a0
    Print_string:
        li      $v0,4
        syscall
        jr      $ra
    
    # end the program, no explicit return status
    Exit:
        li      $v0,10
        syscall
    

    【讨论】:

    • 这极大地帮助了我的理解。感谢您的全面投入!
    猜你喜欢
    • 2012-03-31
    • 2021-09-12
    • 1970-01-01
    • 2016-07-08
    • 2017-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多