C strings aren't bad. They can't be, because they don't exist. C doesn't have strings. And that is the issue.
As you say, things get a lot better when you actually introduce strings as a concrete concept rather than a set of lose conventions.
C strings aren't bad. They can't be, because they don't exist. C doesn't have strings. And that is the issue.
As you say, things get a lot better when you actually introduce strings as a concrete concept rather than a set of lose conventions.
C has string literals though, and those bake a specific string representation into the language (of course libraries can use their own string representation, but those then need at least some conversion function from string literals).
So that strcmp expects a string rather than a pointer to a character is just convention. In languages which actually has strings as a concrete concept, like say Pascal and derivatives, you can actually differentiate between those two cases.
[1]: https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#...
char s[3] = "foo"; // not null-terminated!Byte count.
In practice, in C context, character == char == byte. Other concepts have to use different names to avoid confusion with the language spec.
WUFFS doesn't have strings. That's what a language which doesn't have strings looks like, you can't write "Hello, world" in WUFFS because it involves Strings, which WUFFS doesn't have, and I/O, which WUFFS also doesn't have.
A pretence that C doesn't have strings because it lacks a concrete string type in the language itself also seems like you'd be claiming C++ doesn't have strings, Zig doesn't have strings, and Rust came pretty close to not having strings (for a while it was mooted to make Rust's str just a slice [u8] but today Rust does bless str as a distinct type even though e.g. &str and &[u8] aren't very different)
Zig and Rust I don't know enough about.
And I'm not pretending. C has string literals which are of a non-distinct type. You can't distinguish between a string literal and an array of characters. This is the crucial bit.
The result is that the standard library, and lots of other code, relies on convention alone to pass strings around. This has been and continues to be the source for countless serious bugs. The kind of bugs which are a total non-issue in languages which has strings.
[1]: https://en.cppreference.com/w/cpp/language/user_literal