I am attempting to write a code with several different segment, such as combine two differents strings, compare two strings, find the length of a string. Right now, I am working on the part to get the string length, but when I run the code I have so far on Mars and QTSpim, instead of getting a length of 1, I am getting 0 to the first power displayed as the answer. What have I done wrong?

.data
S1: .asciiz "I "
S2: .asciiz "love "
S3: .asciiz "assembly"
string: .asciiz "Our three strings are:\n"
S4: .asciiz "\nThe three strings combined are: "
S5: .asciiz "\nWhen string 3 is copied into string 5, string 5 is: "
S6: .asciiz "\nWhen string 4 is copied into string 6, string 6 is: "
L1: .asciiz "\nThe length of the first string is: "
L2: .asciiz "\nThe length of string 4 is: "
.text
main:

#display all three strings first
    li $v0, 4
    la $a0, string
    syscall
    la $a0, S1
    syscall 
    la $a0, S2
    syscall
    la $a0, S3
    syscall
    la $a0, S1 #load address of string
    jal strlen #call string length procedure
    jal print
    addi $a1, $a0, 0 #move address of string to $a1
    addi $v1, $v0, 0 #move length of string to $v1
    addi $v0, $0, 11 #syscall code for message
    la $a0, L1 #address of message
    syscall

    li $v0, 10
    syscall

    strlen:
    addi $t0, $t0, 1 #initialize count to start with 1 for first character

loop:
    lb $t0, 0($a0) #load the next character to t0
    addi $a0, $a0, 1 #load increment string pointer
    addi $t0, $t0, 1 #increment count
    beqz $t1, exit #end loop if null character is reached
    j loop # return to top of loop

exit: jr $ra

print: 
    li $v0, 4
    la $a0, L1
    syscall

    li $v0, 1
    move $a0, $t1
    syscall

    jr $ra

Recommended Answers

All 8 Replies

For the first line of strlen(), change the code to

 addi $t0, $zero, 1 #initialize count to start with 1 for first character

The problem you are experiencing is likely to be because the $t0 register is not guaranteed to be zeroed out when the program starts. You are also loading the character into $t0 in the second line of code, when you presumably want to put it in $t1:

lb $t1, 0($a0) #load the next character to t1

Finally, the usual practice is to use $v0 and $v1 for the return values of functions. I would recommend changing the program thusly:

.data
S1: .asciiz "I "
S2: .asciiz "love "
S3: .asciiz "assembly"
string: .asciiz "Our three strings are:\n"
S4: .asciiz "\nThe three strings combined are: "
S5: .asciiz "\nWhen string 3 is copied into string 5, string 5 is: "
S6: .asciiz "\nWhen string 4 is copied into string 6, string 6 is: "
L1: .asciiz "\nThe length of the first string is: "
L2: .asciiz "\nThe length of string 4 is: "
.text
main:

#display all three strings first
    li $v0, 4
    la $a0, string
    syscall
    la $a0, S1
    syscall 
    la $a0, S2
    syscall
    la $a0, S3
    syscall
    la $a0, S1 #load address of string
    jal strlen #call string length procedure
    move $a0, $v0
    jal print
    addi $a1, $a0, 0 #move address of string to $a1
    addi $v1, $v0, 0 #move length of string to $v1
    addi $v0, $0, 11 #syscall code for message
    la $a0, L1 #address of message
    syscall

    li $v0, 10
    syscall

#########################################
## int strlen(char*)
strlen:
    addi $t0, $zero, 1 #initialize count to start with 1 for first character
    j strlen.test

strlen.loop:
    addi $a0, $a0, 1 #load increment string pointer
    addi $t0, $t0, 1 #increment count
strlen.test:
    lb $t1, 0($a0)   #load the next character to t0
    bnez $t1, strlen.loop #end loop if null character is reached
    move $v0, $t0

    jr $ra

#########################################
## void print_str (char*)
print: 
    addi $sp, $sp, -12
    sw $fp, 8($sp)
    addi $fp, $sp, 16
    sw $ra, 0($fp)
    sw $s0, -4($fp)    

    move $s0, $a0   # store the argument in a save register
    li $v0, 4
    la $a0, L1
    syscall

    li $v0, 1
    move $a0, $s0   # retrieve the argument from $s0
    syscall

    lw $s0, -4($fp)
    lw $ra, 0($fp)
    lw $fp, 8($sp)
    addi $sp, $sp, 12   

    jr $ra

I'm still getting 0. The first string is 'I ', so I should be getting it to display 'The length of the first string is: 1', instead of it displaying 0.

Okay, now I'm getting the code to print 1 for the answer. There is just one other problem now. It prints the length twice. When it displays it, it gives:
'The length of the first string is: 268500992'
'The length of the first string is: 1'
Why is it printing the first one. I only need it to print the second one. Thanks in advance for any help.

The most likely cause is that you accidentally deleted or commented out the function return (jr $ra) at the end of strlen().

BTW, the size of the string "I " is two, not one; you have to count the space as a character. I've fixed the code as I had it so it now works correctly on QtSpim (I don't think the .align 4 directive works in Mars, though):

.data
.align 4
S1: .asciiz "I "
S2: .asciiz "love "
S3: .asciiz "assembly"
string: .asciiz "Our three strings are:\n"
S4: .asciiz "\nThe three strings combined are: "
S5: .asciiz "\nWhen string 3 is copied into string 5, string 5 is: "
S6: .asciiz "\nWhen string 4 is copied into string 6, string 6 is: "
L1: .asciiz "\nThe length of the first string is: "
L2: .asciiz "\nThe length of string 4 is: "
.text
main:

#display all three strings first
    li $v0, 4
    la $a0, string
    syscall
    la $a0, S1
    syscall 
    la $a0, S2
    syscall
    la $a0, S3
    syscall
    la $a0, S1 #load address of string
    jal strlen #call string length procedure
    move $a0, $v0
    jal print
    addi $a1, $a0, 0 #move address of string to $a1
    addi $v1, $v0, 0 #move length of string to $v1
    addi $v0, $0, 11 #syscall code for message
    la $a0, L1 #address of message
    syscall

    li $v0, 10
    syscall

#########################################
## int strlen(char*)
strlen:
    move $t0, $zero  #initialize count to start with 0 for first character
    j strlen.test


strlen.loop:
    addi $a0, $a0, 1 #load increment string pointer
    addi $t0, $t0, 1 #increment count
strlen.test:
    lb $t1, 0($a0)   #load the next character to t0
    bnez $t1, strlen.loop #end loop if null character is reached
    move $v0, $t0

    jr $ra

#########################################
## void print_str (char*)
print: 
    addi $sp, $sp, -12
    sw $fp, 8($sp)
    addi $fp, $sp, 16
    sw $ra, 0($fp)
    sw $s0, -4($fp)    

    move $s0, $a0   # store the argument in a save register
    li $v0, 4
    la $a0, L1
    syscall

    li $v0, 1
    move $a0, $s0   # retrieve the argument from $s0
    syscall

    lw $s0, -4($fp)
    lw $ra, 0($fp)
    lw $fp, 8($sp)
    addi $sp, $sp, 12   

    jr $ra

Yeah. That was the problem. I accidentally left of the jr $ra. Thanks for your help. Now I just have to work on copying the strings and concatenating the strings, as well as getting the final length for the concatenated string.

In case I do have extra questions about what to do on this one, the instructions for this extra credit assignmnet given to my class are:
Write a program that will define the following string manipulation functions. Each is analogous to the
corresponding C++ string function.
STRLEN( Str &, Len &) Sent the address of a string, it returns the length in a call-by-reference param.
STRCPY( Dest &, Source & ) Sent the address of the Source string, it places a copy of it in the Destination
string.
STRCAT( Dest &, Source & )Sent the address of the Source String, a copy of it is attached to the end of
the Destination string.
The test program will do at least the following:
S1 = “I ”
S2 = “love “
S3 = “assembly “
S4 = S1 + S2 + S3 (using STRCAT)
S5 = S3 (using STRCPY)
S6 = S4 (using STRCPY )
L1 = STRLEN( S1)
L4 = STRLEN( S4)

No problem. Fortunately, each of these by itself is fairly easy; actually, strcat() and strcpy() are very similar, enough so that the easiest solution for strcat() in assembly language is embed strcpy() at the end of it, like so:

###################################
## char* strcat(char*, char*)
strcat:
    # save a copy of $a0 on the stack
    jal strlen
    add $a0, $a0, $v0  # reset the dest to the end of dest
    j strcpy.test    #### WARNING: Fall-thru to strcpy() ###

###################################
## char* strcpy(char*, char*)
strcpy:
    # save a copy of $a0 on the stack

strcpy.loop:
    # copy the string in a loop

strcpy.test:
    # test for the end of the loop

    # retrieve the original value of dest and put it in $v0
    # restore the stack

    jr $ra

Thanks. I'm taking this one step at a time though, as this is the first semester in college courses that I'm doing assembly. Right now I'm working on the copying S3 into s5. I've probably done something wrong, especially seeing as how I used the methods for string length to copy, so that it prints out, 'When string 3 is copied into string 5, string 5 is: 1M' instead of displaying 'assembly'. Is it because I didn't save onto the stack(as this is the second assignment we've done involving stacks, so I'm just getting used to them). I'm pretty certain I messed up in the strcopy1 segment.

.data
S1: .asciiz "I "
S2: .asciiz "love "
S3: .asciiz "assembly"
string: .asciiz "\nOur three strings are:\n"
S4: .asciiz "\nThe three strings combined are: "
S5: .asciiz "\nWhen string 3 is copied into string 5, string 5 is: "
S6: .asciiz "\nWhen string 4 is copied into string 6, string 6 is: "
L1: .asciiz "\nThe length of the first string is: "
L2: .asciiz "\nThe length of string 4 is: "
.text
main:

#display all three strings first
    li $v0, 4
    la $a0, string
    syscall
    la $a0, S1
    syscall 
    la $a0, S2
    syscall
    la $a0, S3
    syscall
    la $a0, S1 #load address of string
    jal strlen1 #call string length procedure
    move $a0, $v0
    jal print1
    addi $a1, $a0, 0 #move address of string to $a1
    addi $v1, $v0, 0 #move length of string to $v1
    addi $v0, $0, 11 #syscall code for message
    la $a0, L1 #address of message
    syscall
    la $a0, S3
    jal strcopy1
    jal print2
    addi $a1, $a0, 0 #move address of string to $a1
    addi $v1, $v0, 0 #move length of string to $v1
    addi $v0, $0, 11 #syscall code for message
    la $a0, S5 #address of message
    syscall
    li $v0, 10
    syscall

    strlen1:
    addi $t0, $0, 1 #initialize count to start with 1 for first character
    j strlen1.test

strlen1.loop:
    addi $a0, $a0, 1 #load increment string pointer
    addi $t0, $t0, 1 #increment count
strlen1.test:
    lb $t1, 0($a0)
    beqz $t1, strlen1.loop #end loop if null character is reached
    move $v0, $t0

    jr $ra
print1: 
    addi $sp, $sp, -12
    sw $fp, 8($sp)
    addi $fp, $sp, 16
    sw $ra, 0($fp)
    sw $s0, -4($fp)

    move $s0, $a0 #store argument in a save register
    li $v0, 4
    la $a0, L1
    syscall

    li $v0, 1
    move $a0, $s0 # get argument from $s0
    syscall

    lw $s0, -4($fp)
    lw $ra, 0($fp)
    lw $fp, 8($sp)
    addi $sp, $sp, 12

    jr $ra

strcopy1:
    addi $t0, $0, 1 #initialize count to start with 1 for first character
    j strcopy1.test

strcopy1.loop:
    addi $a0, $a0, 1 #load increment string pointer
    addi $t0, $t0, 1 #increment count
strcopy1.test:
    lb $t1, 0($a0)
    beqz $t1, strcopy1.loop #end loop if null character is reached
    move $v0, $t0

    jr $ra

print2: 
    addi $sp, $sp, -12
    sw $fp, 8($sp)
    addi $fp, $sp, 16
    sw $ra, 0($fp)
    sw $s0, -4($fp)

    move $s0, $a0 #store argument in a save register
    li $v0, 4
    la $a0, S5
    syscall

    li $v0, 1
    move $a0, $s0 # get argument from $s0
    syscall

    lw $s0, -4($fp)
    lw $ra, 0($fp)
    lw $fp, 8($sp)
    addi $sp, $sp, 12

    jr $ra
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.