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

18,084

Solution 1

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

Solution 2

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.

Share:
18,084

Related videos on Youtube

MuhammadNe
Author by

MuhammadNe

Updated on June 04, 2022

Comments

  • MuhammadNe
    MuhammadNe almost 2 years

    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?

    • mclark1129
      mclark1129 almost 9 years
      possible duplicate of char array in MIPS
    • MuhammadNe
      MuhammadNe almost 9 years
      I saw the website and it helped a little, but now I am stuck in printing the cells one by one, I have updated the question, I hope you see it.
    • mclark1129
      mclark1129 almost 9 years
      Thank you for updating the question, I updated the title to be more in line with the actual question now. This is not a duplicate of the question I posted, so I will retract my vote.
    • Admin
      Admin almost 9 years
      will just incrementing $t0 (in a loop) and using a 0 offset in the lb instruction do the trick?
  • MuhammadNe
    MuhammadNe almost 9 years
    This actually works, the problem i had was doing the offset, thank you for the solution and the great explanation.
  • Peter Cordes
    Peter Cordes over 3 years
    t1($t0) is not a valid MIPS addressing mode; it only has constant(register) for a 16-bit sign-extended immediate constant. That's why you normally do pointer increments (by 4) instead of using sll/add to redo indexing each iteration. (For word elements. Just add for 1-byte elements like the question's char array) But yes, left-shift by n = multiply by 2^n, and you should always use shifts instead of actual mul or mult for known powers of 2.