Not all languages use NULL terminated strings. I think Rust actually stores the string length alongside a pointer to the start of the string data. You can do the same in C, but you'd have to do it manually using a struct. In assembly you could do the same thing since you get to decide basically everything.
And super educational. Since then I've been pondering which problems require dropping down to the assembly level. E.g. implementing a JIT compiler, a coroutine runtime, etc.