Почему в Си допускается переполнение массива?
Потому что это проверка на переполнение даёт лишние накладные расходы при выполнении. Изначально язык разрабатывался с расчётом на эффективность, с девизом что-то типа: «не нужно платить за то, чем не пользуешься».
По сути, Си — это просто высокоуровневый ассемблер. В ассемблере нет понятия ошибок вообще, всё на плечах разработчика. Если ему нужно проверять на переполнение, он сам должен реализовать этот функционал, а не терять на этом производительность, когда ему это не нужно.
Почему строковый массив может переполняться без какой-либо ошибки?
Потому что диагностика такой ошибки не требуется от реализаци. Есть реализации диагностирующе такие ошибки, например gcc + ASAN.