Почему в С допускают такое?
То что у вас написано квалифицируется стандартом как Undefined behavior (с99 6.7.3:5):
If an attempt is made to modify an object defined with a const-qualified type through use
of an lvalue with non-const-qualified type, the behavior is undefined.
Почему технически можно так сделать и этот код работает -- потому что массив string имеет автоматическое время жизни и компилятор помещает его на стек. Т.е. память фактически не является константной.
Почему функция strchr принимает
const char *
, а возвращает
char *
? Чтобы показать, что сама она свой аргумент не изменяет, но чтобы не заставлять всех её пользователей делать приведение типа у результата. Я бы сказал, что проблема в этой функции, но она настолько старая, что никто не будет чинить её прототип.
В С++ можно было бы решить эту проблему предоставив два перегруженных варианта strchr --
char *strchr(char *, char)
и
const char *strchr(const char *, char)
, но в С нет перегрузки функций.