How I handle text in C

I hate dealing with C strings, but they're kind of unavoidable, so I've come up with a data structure with a bit of additional semantics that I call "strands" to deal with them as well as other string-like things at once.

typedef struct Strand Strand;
struct Strand {
    char *s; /* start */
    char *e; /* end */
};
int endsat(Strand s, usize_t i) {
    return s.e != NULL ? s.s + i == s.e : s[i] == '\0';
}

A strand can represent:

Any other state is invalid.

Strands can, like C strings and unlike {start, length} fat pointers, be shrunk rightward in a single operation, and they handily represent each of C strings, sized character buffers, and slices into either with a single clean interface. This is why I've settled on them for tasks like syntax parsing and UTF-8 decoding in C. I'm definitely not the first person to store start and end indices, and I'm probably also not the first to overload the end index in this way, but I've never seen it in the wild, and I think it's a nice solution, so I'm putting it out there.