How can I access the individual elements of an array in a loop?

25.4k views Asked by At

I need to print the cells of an array, I have an array which contains the word "HELLO_WORLD", I manage to print an index by its own but I can't manage to print all the cells one by one, here is the code :

loop:
la    $t0, hexdigits          # address of the first element
lb    $a0, 5($t0)            # hexdigits[10] (which is 'A')
li    $v0, 11 #system call service
syscall
addi $a0, $a0, 2
li    $v0, 11                 # I will assume syscall 11 is printchar (most simulators support it)
syscall                       # issue a system call
j end

Is there anyway to use the instruction lb $a0, $s0($t0) with a register that I can increment anytime I want? and not just a number?

3

There are 3 answers

2
Rakholiya Jenish On BEST ANSWER

To access any individual element of array, you can use it as:

la $t3, array         # put address of array into $t3

If array is a byte array, like:

array:   .byte    'H','E','L','L','O'

to access the ith element:

lb $a0, i($t3)        # this load the byte at address that is (i+$t3)

because each element is of 1 byte, so to access ith byte, access the address that is i offset to address of array.

You can also access it as:

addi $t1,$t3,i
lb $a0,0($t1)

If array is a word array, like:

array:   .word    1,2,3,4,5,6,7,8,9

to access the ith element:

lw $a0, j($t3)        #j=4*i, you will have to write j manually

because each element if of 4 byte and to access ith element, you will have to move i*4 byte from the starting address of array.

There are also some other ways of accessing it:

li $t2, i            # put the index in $t2
add $t2, $t2, $t2    # double the index
add $t2, $t2, $t2    # double the index again (now 4x)
add $t1, $t3, $t2    # get address of ith location
lw $a0, 0($t1)

Example1:

.data
array:  .byte 'H','E','L','L','O','_','W','O','R','L','D'
string: .asciiz "HELLO_WORLD"
size:   .word   11
array1: .word   1,2,3,4,0,6,7,8,9

.text
.globl main
main:
    li $v0, 11

    la $a2,array

    lb $a0,0($a2)        #access 1st element of array or array[0]
    syscall
    lb $a0,1($a2)        #access 2nd element of byte array or array[1]
    syscall
    lb $a0,2($a2)        #access 3rd element of byte array or array[2]
    syscall
    lb $a0,10($a2)       #access 11th element of byte array or array[10]
    syscall
    li $a0,10
    syscall
    syscall
    li $v0,1
    la $a3,array1
    lw $a0,0($a3)        #access 1st element of word array or array[0]
    syscall
    lw $a0,4($a3)        #access 2nd element of word array or array[1]
    syscall
    lw $a0,8($a3)        #access 3rd element of word array or array[2]
    syscall
    lw $a0,12($a3)       #access 4th element of word array or array[3]
    syscall
    jr $ra

Example: Prints the byte array:

    li $v0, 11
    la $a2,array
    lw $t0,size
loop1:                         #print array
    lb $a0, 0($a2)             #load byte at address stored in $a2
    syscall
    add $t0,$t0,-1
    add $a2,$a2,1              #go to the next byte, since it is a byte array it will go to the address of next element
#to use it for printing word array instead of adding 1 add 4
    bgtz $t0, loop1
0
mclark1129 On

Here is my best attempt at a solution for what you are after.

.data
mystring: .asciiz "HELLO_WORLD"    # zero-terminated string

.text
la $t0, mystring  # Load the array
li $t1, 0         # Create the loop counter
li $v0, 11        # Syscall code for print character       

loop:

    add $t2, $t0, $t1    # Load the address for the element at the current index
    lb $a0, 0($t2)       # Load the value of the array at the current index into $a0
                         # (For printing)

    beqz $a0, exit       # If the value at the current index is null, you have 
                         # reached the end of the string, so exit out

    syscall              # Print the character in $a0 (Syscall code in $v0: 11)

    addi $t1, $t1, 1     # Increment the counter

    j loop               # Jump to the beginning of the loop    

exit: # Should be reached once you have hit the end of the string

Disclaimer: I do not know MIPS assembly, I tried to pick up as much as I could to research your question. I could only test this program in an online emulator that did not support printing to the screen (syscall). Do not just blindly paste this code and respond with "Nope, doesn't work". If there are any problems please try to be specific and I'll try to figure out the issue.


Editor's notes: looks ok to me, after fixing .asciiz to make sure there's a zero terminator even if other non-zero data is placed right after it in the .data section.

v0=11 / syscall leaves $v0 unmodified, so the li $v0, 11 can be hoisted out of the loop. Some system calls put a return value in $v0, but this one doesn't. (MARS syscall docs)

Instead of a counter starting at 0, we could directly increment the $t1 pointer.

To make this more efficient, we could "rotate" the loop so there was a bnez $a0, loop at the bottom (no j needed), probably by peeling the first iteration: load and check a char before the loop, then fall into the loop with printing as the first thing. Then increment, load and check the next char and either fall out of the loop or jump to the top to print it, too.

1
tonythestark On

I am beginner at Mips assebly , but I from what I 've learned i think you can do it as such:
Every element of the array is been given 4bytes (it maybe be actually less but no other element it's going to store anything on these 4 bytes, these are dedicated to only one element).
So, between the adresses of two elements k,k+1, there is a distance of 4bytes(always).
As mentioned above, if you want to reach the i-th element you need to add to the adress of the first (A[0]) the offset distance which is 4*i.
One way to create this offset distance other than mul instruction is :

sll $t1, $t0, 2

this actually means "shift left the value in register $t0 , 2 bits (fill the rest with 0's) and store the result in register $t1 . But you can easily notice , that if you shift left and fill with zero , for every shift you actually multiply the current value by 2 ( please note that we use this if we know that we have enough space, to avoid overfloating)

So if for instance in $t0, you had 0001 in $t1 you will gain 0100 So basically : you need

sll $t1, $t0, 2 # [t1]=4i
lb $a0, t1($t0)  # a0 = A[i]

*if you are a more experienced Mips programmer, and I am wrong , edit my post or comment to make sure everyone of us gets better