The code vs data distinction is a hardware thing, this is not about C. More precisely, it is the difference between a Harvard and a Von Neumann architecture. A Harvard architecture has completely separate paths between instructions and data: different buses, different memories. A Von Neumann architecture has common instruction and data paths, and therefore, naturally, data is executable. You can write C code for both.
Modern PC-style hardware is kind of a hybrid, acts like Harvard with regard to cache, and like Von Neumann with regard to RAM. Furthermore, it has a fancy MMU that allows for things like the NX bit. All C compilers/linkers I am aware of know the difference between code and data and are able to put each one in the appropriate section, what is done after that is the OS/hardware responsibility.
As for zero-terminated strings, I also think it is mostly a mistake, though it does have a few advantages. You can still work with size+pointer though, using mem- instead of the str- functions, and "%.*s" in printf(), not ideal though.