How can I access the individual elements of an array in a loop?
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.
Related videos on Youtube
MuhammadNe
Updated on June 04, 2022Comments
-
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 almost 9 yearspossible duplicate of char array in MIPS
-
MuhammadNe almost 9 yearsI 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 almost 9 yearsThank 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 almost 9 yearswill just incrementing $t0 (in a loop) and using a 0 offset in the lb instruction do the trick?
-
-
MuhammadNe almost 9 yearsThis actually works, the problem i had was doing the offset, thank you for the solution and the great explanation.
-
Peter Cordes over 3 years
t1($t0)
is not a valid MIPS addressing mode; it only hasconstant(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 byn
= multiply by2^n
, and you should always use shifts instead of actualmul
ormult
for known powers of 2.