C не разрешает доступ к памяти за концом массива. Однако он позволяет указателю указывать на один элемент за концом массива. Различие важно.
Таким образом, все в порядке:
char array[N];
char *p;
char *end;
for (p = array, end = array + N; p < end; ++p)
do_something(p);
(Выполнение *end
было бы ошибкой.)
И это показывает причину, по которой эта функция полезна: указатель, указывающий на (несуществующий) элемент после конца массива, полезен для сравнений, например, в циклах.
Технически говоря, это все, что позволяет стандарт C. Однако на практике реализация C (компилятор и среда выполнения) не проверяет, обращаетесь ли вы к памяти за концом массива, будь то один элемент или более. Должна быть проверка границ, и это замедлит выполнение программы. Типы программ, для которых C лучше всего подходит (системное программирование, библиотеки общего назначения), имеют тенденцию получать больше пользы от скорости, чем дает проверка границ безопасности и безопасности.
Это означает, что C, возможно, не является хорошим инструментом для программирования приложений общего назначения.