2013-06-18 3 views
7

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

Если р и д указывают на элементы одного и того же массива, тогда как отношения ==, ! =, <,> = и т.д., работают надлежащим образом. Например, p < q истинно, если p указывает на более ранний элемент массива, чем q. Любой указатель может быть , осмысленно сравниваемый для равенства или неравенства с нулем. Но поведение не определено для арифметики или сравнений с указателями, которые не указывают на элементы того же массива. (Существует одно исключение: адрес первого элемента мимо конца массива можно использовать в арифметике с указателями.)

Что является причиной этого исключения? Является ли дополнительный кусок памяти выделенным для конца любого массива, когда их размер определен? Если да, то с какой целью? Должно ли это закончить массив нулевым символом?

+1

Простейший способ понять это: a [b] = a + b. Посмотрите на страницу 98 для объяснения – SheetJS

+2

@Nirk: А? Что это связано с этим? – jason

ответ

8

Причина заключается в том, чтобы вы могли увеличивать указатель в цикле, как это:

char a[42], *p; 

for (p = a; p < &a[sizeof a]; p++) // or p != &a[sizeof a] 
{ 
    /* ... */ 
} 

Без дополнительного правила, это было бы неопределенное поведение, потому что указатель будет недействительным.

0

В конце массива нет дополнительной памяти. Он просто говорит, что вы можете указать адрес, обозначенный «Конец» ниже в арифметике указателя. Начать указывает на первый элемент массива. Конец указывает на первый элемент конец массива.

----------------- 
| | | | | 
----------------- 
^    ^
Begin   End 
4

лишний кусок памяти, выделяемой в конце любого массива, когда их размер определяется?

Нет. Контекст, который вы цитировали, важен. Исключение, выделенное жирным шрифтом, относится к арифметике указателей (и отношениям). Он говорит, что если вы делаете указательные отношения между указателями, которые делают не, то указывайте на членов того же массива, затем получите udb. Однако есть одно исключение, которое есть, если любой из указателей указывает на первый элемент за концом массива.

Если да, то с какой целью?

null ответ, так как он предполагает ложное помещение.

Заканчивается ли массив нулевым символом?

No.

Причина этого заключается в том, так что сравнение с конца массива является законным, то есть сравнение с &a[sizeof a] когда a является массивом. Обратите внимание, что &a[sizeof a] - это первый элемент за концом массива.Если p является указателем на элемент a или также первым элементом за конец массива, то p можно сравнить с &a[sizeof a].

Я цитирую из раздела C99 specification, раздел 6.5.8.5.

При сравнении двух указателей результат зависит от относительных местоположений в адресном пространстве объектов, на которые указывает. Если два указателя на объект или неполные типы указывают на один и тот же объект или оба указывают один за последним элементом одного и того же объекта массива, они сравнивают равные. Если объекты, на которые указывают, являются членами одного и того же совокупного объекта, указатели на элементы структуры, объявленные позже, сравниваются больше, чем указатели на элементы, объявленные ранее в структуре, а указатели на элементы массива с большими значениями индекса сравниваются больше, чем указатели на элементы одного и того же массива с нижними значениями индекса. Если выражение P указывает на элемент объекта массива, а выражение Q указывает на последний элемент одного и того же объекта массива, выражение указателя Q + 1 сравнивает более P. Во всех остальных случаях поведение не определено.

0

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

Примером того, где это обещание является важным, является то, что объект может быть выделен в самом конце памяти, так что адрес одного из конца может вызвать арифметическое переполнение при вычислении адреса. Если вы должны были пропустить указатель через этот массив, то после последней итерации арифметическое переполнение может привести к тому, что указатель обернется вокруг и укажет на NULL.

Это может привести к инвертированию результатов сравнения, и он может отключать всевозможные сигнальные колокола с помощью проверок на основе массива или просто вычислять неправильный адрес, если процессор использует, например, насыщающую арифметику.

Поэтому компилятор и компоновщик обязаны гарантировать, что этого не может произойти, и обязанность программиста состоит в том, чтобы гарантировать, что компилятор и компоновщик несут ответственность только в одном простом случае, t должны поддерживать ту же гарантию, когда вы запустите n элементов дальше от конца.

Смежные вопросы