# Byte length of a string

[Courses](https://asm-editor.specy.app/learn/courses.md) › [MIPS assembly](https://asm-editor.specy.app/learn/courses/mips.md) › Examples

Web page: https://asm-editor.specy.app/learn/courses/mips/examples/string-length

> Measure a zero-terminated string in bytes by subtracting its start address from its terminator address.

The same program in: [M68K](https://asm-editor.specy.app/learn/courses/m68k/examples/string-length.md), [RISC-V](https://asm-editor.specy.app/learn/courses/risc-v/examples/string-length.md), [Z80](https://asm-editor.specy.app/learn/courses/z80/examples/string-length.md), [x86-64](https://asm-editor.specy.app/learn/courses/x86/examples/string-length.md)

A zero-terminated string stores its end as a zero byte. To find its **byte length**, walk a pointer
from the first byte to that zero, then subtract the starting address from the ending address.

```mips
.data
text:  .asciiz "Assembly is fun"
after: .asciiz " and so is C"

.text
main:
    la $t0, text         # current byte: start at text
    move $t1, $t0        # remember the starting address
scan:
    lbu $t2, 0($t0)      # load the current byte
    beqz $t2, at_end     # stop when that byte is zero
    addiu $t0, $t0, 1    # advance by one byte
    j scan

at_end:
    subu $t3, $t0, $t1   # byte length = end address - start address

    li $v0, 10           # exit
    syscall
```

*Testcase for the program above (JSON):*

```json
{
    "expectedRegisters": {
        "$t0": "0x1001000f",
        "$t1": "0x10010000",
        "$t3": 15,
        "$v0": 10
    }
}
```

`la $t0, text` puts the address of the first byte in `$t0`, and `move` saves that address in `$t1`.
At `scan`, `lbu` reads one byte from the address in `$t0`. If the byte is zero, `beqz` goes to
`at_end`. Otherwise, `addiu` moves `$t0` to the next byte and `j scan` checks again. String bytes
occupy adjacent addresses, so adding 1 moves exactly one byte forward.

Here is the loop's stopping rule:

| Byte at `$t0`     | What happens                                |
| ----------------- | ------------------------------------------- |
| A letter or space | Advance `$t0` by 1, then check again.       |
| Zero terminator   | Stop with `$t0` still pointing at the zero. |

`.asciiz "Assembly is fun"` stores fifteen content bytes followed by one zero byte:

`41 73 73 65 6d 62 6c 79 20 69 73 20 66 75 6e 00`

The pointer advances fifteen times before it finds the zero. `$t1` still holds the starting address,
so `subu $t3, $t0, $t1` gives the number of one-byte advances: **15**. The zero does not count,
because the branch stops the loop before another advance.

Now make the loop your own in the Playground. Change the declaration to
`text: .asciiz "Hi MIPS"`. Before running, predict the byte length. Then erase the four instructions
after `scan:` and the `subu` instruction after `at_end:`, leaving the labels and exit instructions
in place. Write those five instructions again. Keep `$t0` as the current address, `$t1` as the saved
start, and `$t3` as the answer. Load one byte, branch when it is zero, advance one byte otherwise,
and repeat. At `at_end`, subtract the addresses. Use
**Run** to check your edit: `$t3` should show `00000007` (7 bytes) in the default hexadecimal
register display.

Optional memory inspection: keep your working loop and change only the `text` declaration back to
`text: .asciiz "Assembly is fun"`. In the default
Playground layout, `text` begins at `0x10010000`. The terminator sits at `0x1001000f`, so `$t0`
ends there while `$t1` remains at `0x10010000`. The register display shows these addresses as
`1001000F` and `10010000`, without a `0x` prefix.

For an empty-string check, replace the declaration with `text: .asciiz ""` and use **Run**. The
first loaded byte is already zero, so `$t0` never advances and `$t3` is 0.

For a controlled demonstration of the terminator, restore the original string and change only
`text: .asciiz` to `text: .ascii`. Predict the result, then use **Run**. `.ascii` leaves out the
zero, so this loop continues into the adjacent `after` declaration. It counts the 15 bytes of
`text` and the 12 bytes of `after`, stopping at `after`'s zero: `$t3` is 27. Restore `.asciiz`
afterwards. A string meant for this loop needs its own zero terminator.

This program measures stored bytes. Other text encodings can use more than one byte for a visible
character.

## Instructions in this Lecture

- MIPS: [`la`](https://asm-editor.specy.app/documentation/mips/instruction/la.md), [`move`](https://asm-editor.specy.app/documentation/mips/instruction/move.md), [`lbu`](https://asm-editor.specy.app/documentation/mips/instruction/lbu.md), [`beqz`](https://asm-editor.specy.app/documentation/mips/instruction/beqz.md), [`addiu`](https://asm-editor.specy.app/documentation/mips/instruction/addiu.md), [`j`](https://asm-editor.specy.app/documentation/mips/instruction/j.md), [`subu`](https://asm-editor.specy.app/documentation/mips/instruction/subu.md), [`li`](https://asm-editor.specy.app/documentation/mips/instruction/li.md), [`syscall`](https://asm-editor.specy.app/documentation/mips/instruction/syscall.md)

Previous: [The largest element](https://asm-editor.specy.app/learn/courses/mips/examples/max-of-an-array.md)

Next: [Reverse a string in place](https://asm-editor.specy.app/learn/courses/mips/examples/reverse-a-string.md)
