I like Rust's approach of having purpose-specific string types that may differ (e.g. if your OS is using UTF-16 encoded strings but the C strings are just arrays of bytes). It guarantees that the programmer checks/converts the string is in/to the correct form, or just let the program panic with .unwrap(), when interfacing with the external world. It makes the program safe and makes the potentially expensive string conversion calls explicit. Also, I think valid UTF-8 strings is a good default.
I haven't used Zig yet (I haven't found a good use case for it), it seems closer to C both in spirit and in implementation while removing some foot guns.