Я читал книгу K и R на C и обнаружил, что арифметика указателей в C позволяет получить доступ к одному элементу за пределами массива. Я знаю, что C позволяет делать почти что угодно с памятью, но я просто не понимаю, какова цель этой особенности?
C - элемент за пределами массива
Ответ 1
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, возможно, не является хорошим инструментом для программирования приложений общего назначения.
Ответ 2
Часто полезно обозначить позицию "конец", которая находится за пределами фактического распределения, поэтому вы можете написать код, например:
char * end = begin + size;
for (char * curr = begin; curr < /* or != */ end ; ++curr) {
/* do something in the loop */
}
В стандарте C явно указано, что этот элемент является допустимым адресом памяти, но разыменование его все равно не будет хорошей идеей.
Почему у этого есть такая гарантия? Скажем, у вас была машина с 2 ^ 16 байтами памяти, адреса 0000-FFFF, 16-разрядные указатели. Предположим, вы создали 16-байтовый массив. Можно ли выделить память в FFF0?
Существует 16 байтов, которые свободно смежны, но:
begin + size == FFF0 + 10 (16 in hex) == 10000
который обертывается до 0000 из-за размера указателя. Теперь условие цикла:
curr < end == FFF0 < 0000 == false
Вместо итерации по массиву цикл ничего не сделает. Это нарушит много кода, поэтому в стандарте C указано, что распределение недопустимо.
Ответ 3
вы можете выйти далеко за пределы массива например `
int main()
{
char *string = "string";
int i = 0;
for(i=0; i< 10;i++)
{
printf("%c\n", string[i]);
}
return 0;
}
будет печатать мусор после окончания строки слова, независимо от того, что было в памяти перед рукой.