Доступ к элементу за концом массива в C - PullRequest
12 голосов
/ 20 июня 2009

Я читал книгу K & R по C и обнаружил, что арифметика указателей в C позволяет получить доступ к одному элементу за концом массива. Я знаю, что C позволяет делать с памятью почти все, но я просто не понимаю, какова цель этой особенности?

Ответы [ 3 ]

20 голосов
/ 20 июня 2009

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, возможно, не является хорошим инструментом для программирования приложений общего назначения.

16 голосов
/ 20 июня 2009

Часто полезно обозначать «конечную» позицию, которая на единицу больше фактического распределения, поэтому вы можете написать код, например:

 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 говорит, что распределение недопустимо.

0 голосов
/ 20 июня 2009

вы можете выйти далеко за пределы массива например`

int main()
{
        char *string = "string";
        int i = 0;
        for(i=0; i< 10;i++)
        {
                printf("%c\n", string[i]);
        }
        return 0;
}

напечатает мусор после конца строки слова, что бы ни находилось в памяти перед рукой.

...