Search code examples
assemblymipsmips32

How to save string into an array in mips


I have a problem with this code. I try to enter a string by input and save it into an array, this my code:

    .data
    .align 2
array:  .space 80
size: .word 20
string: .space 20
op: .asciiz "Enter the array length"
prompt: .asciiz "Enter a string:"
text:   .asciiz "The array of string is:"
newline: .asciiz "\n"
    .text
    .globl main

main:
    add $t0, $zero, $zero # index of array
    addi $t1, $zero, 1 # counter=1

    li $v0, 4
    la $a0, op
    syscall
    jal new_line

    li $v0, 5
    syscall

    addi $s0, $v0, 0 # $v0 contains integer read
read_string: 
    bgt $t1, $s0, L1 # if ($t1 > length)then go to L1

    li $v0, 4
    la $a0, prompt
    syscall

    la $a0, string
    li $a1, 20
    li $v0, 8
    syscall

    sw $a0, array($t0)
    addi $t0, $t0, 4
    addi $t1, $t1, 1

    j read_string

L1: #### here i want to print the array ####
    add $t0, $zero, $zero # index of array
    addi $t1, $zero, 1 # counter=1

    la $a0, text
    li $v0, 4
    syscall
    jal new_line

    while: bgt $t1, $s0, done
    lw $t2, array($t0)

    li $v0, 4
    move $a0, $t2
    syscall
    jal new_line

    addi $t0, $t0, 4
    addi $t1, $t1, 1
    j while

    new_line: la $a0, newline
    li $v0, 4
    syscall
    jr $ra

done: li $v0, 10
    syscall

The trouble is that this program show me the last string that I've entered by input, for example

Enter the array length:
2
Enter a string:asd
Enter a string:123
The array of string is:
123

123

Please I need some help, thanks a lot and have a nice day.


Solution

  • Your array indexing logic appears to be okay, but the problem was that you were always storing every entry with the same address, the address of string. The solution is a larger string area and incrementing a pointer to it when storing the strings.

    I've corrected your code [untested]. Please pardon the gratuitous style cleanup, but I needed to understand your logic before trying to fix it. I've added more comments [I'm an old time asm guy, and I always comment every line] and annotated your code with [OLD] and my replacements with [NEW].

        .data
        .align 2
    array:      .space  80
    size:       .word   20
    ###string:  .space  20          # [OLD]
    string:     .space  20000       # [NEW]
    op:         .asciiz "Enter the array length:"
    prompt:     .asciiz "Enter a string:"
    text:       .asciiz "The array of string is:"
    newline:    .asciiz "\n"
    
        .text
        .globl main
    main:
        # prompt user for array length
        li      $v0,4
        la      $a0,op
        syscall
        jal     new_line            # output newline
    
        # read in array count
        li      $v0,5
        syscall
        addi    $s0,$v0,0           # $v0 contains the integer we read
    
        add     $t0,$zero,$zero     # index of array
        addi    $t1,$zero,1         # counter=1
        la      $s2,string          # load address of string storage area [NEW]
    
    read_string:
        bgt     $t1,$s0,L1          # if ($t1 > length) then array is done -- fly
    
        # prompt the user for next "string"
        li      $v0,4
        la      $a0,prompt
        syscall
    
        # get the string
    ### la      $a0,string          # place to store string [OLD]
        move    $a0,$s2             # place to store string [NEW]
        li      $a1,20
        li      $v0,8
        syscall
    
        # store pointer to string into array
        sw      $a0,array($t0)
    
        addi    $t0,$t0,4           # advance offset into pointer array
        addi    $t1,$t1,1           # advance iteration count
        addi    $s2,$s2,20          # advance to next string area [NEW]
    
        j       read_string
    
    #### here i want to print the array ####
    L1:
        add     $t0,$zero,$zero     # index of array
        addi    $t1,$zero,1         # counter = 1
    
        # output the title
        la      $a0,text
        li      $v0,4
        syscall
        jal     new_line
    
    while:
        bgt     $t1,$s0,done        # more strings to output?  if no, fly
        lw      $t2,array($t0)      # get pointer to string
    
        # output the string
        li      $v0,4
        move    $a0,$t2
        syscall
        jal     new_line
    
        addi    $t0,$t0,4           # advance array index
        addi    $t1,$t1,1           # advance count
        j       while
    
    # new_line -- output a newline char
    new_line:
        la      $a0,newline
        li      $v0,4
        syscall
        jr      $ra
    
    # program is done
    done:
        li      $v0,10
        syscall
    

    UPDATE For extra credit, when you get the original version working, you can try replacing addi $s2,$s2,20 with jal stradv, where stradv is:

    # stradv -- advance past end of string
    stradv:
        ldb     $t2,0($s2)          # get char
        addi    $s2,$s2,1           # we pre-increment because we want EOS + 1
        bne     $t2,$zero,stradv    # is it EOS?  if no, loop some more
        jr      $ra
    

    This would allow large variable length strings [if you also increased the length on the string read syscall].

    This is how I normally would have coded something like this, but I didn't want to add this until you had the basic code fully working.