Неопределенное поведение с арифметикой указателя на динамически выделяемой памяти - PullRequest
0 голосов
/ 31 января 2019

Я, вероятно, неправильно понимаю это, но предотвращает ли спецификация c99 какую-либо форму арифметики с указателями на динамически выделяемой памяти?

С 6.5.6p7 ...

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

... указатель на объект не в массиве обрабатывается так, как если бы он указывал на массив из 1 элемента (при использовании операторов + и -).Тогда в этом фрагменте:

char *make_array (void) {
    char *p = malloc(2*sizeof(*p));
    p[0] = 1; // valid
    p[1] = 2; // invalid ?
    return p;
}

... второй индекс p[1] недействителен?Поскольку p указывает на объект не в массиве, он рассматривается как указывающий на объект в массиве из одного элемента, а затем из 6.5.6p8 ...

Когда выражение имеет целое числоТип добавляется или вычитается из указателя, результат имеет тип операнда указателя.Если операнд-указатель указывает на элемент объекта массива, и массив достаточно велик, результат указывает на смещение элемента от исходного элемента, так что разность индексов результирующего и исходного элементов массива равна целочисленному выражению.Другими словами, если выражение P указывает на i-й элемент объекта массива, выражения (P) + N (эквивалентно, N + (P)) и (P) -N (где N имеет значение n) указываютсоответственно i + n-м и i-n-м элементам массива, если они существуют.Кроме того, если выражение P указывает на последний элемент объекта массива, выражение (P) +1 указывает один за последним элементом объекта массива, а если выражение Q указывает на один последний элемент последнего элемента массива,выражение (Q) -1 указывает на последний элемент объекта массива.Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или один после последнего элемента объекта массива, оценка не должна вызывать переполнение;в противном случае поведение не определено.Если результат указывает на один последний элемент массива, он не должен использоваться как операнд унарного * оцениваемого оператора.

... у нас неопределенное поведение, так как мы разыменовываемза границей массива (тот, который имеет длину 1).

Редактировать:

ОК, чтобы попытаться объяснить больше, что меня смущает, давайте сделаем это шаг за шагом:

1.) p[1] определяется как означающее *(p+1).
2.) p указывает на объект, который не находится внутри массива, поэтому он обрабатывается так, как если бы он указывал на объектвнутри массива длины 1 с целью оценки p+1.
3.) p+1 создает указатель 1 после массива, на который подразумевается p.
4.) *(p+1) выполняетнедопустимая разыменование.

1 Ответ

0 голосов
/ 31 января 2019

С C99, 7.20.3 - Функции управления памятью (выделено мной):

Указатель, возвращаемый в случае успешного выделения, выровнен соответствующим образом, чтобы его можно было назначить дляуказатель на объект любого типа, который затем используется для доступа к такому объекту или массиву таких объектов в выделенном пространстве (пока пространство не будет явно освобождено).

Этоподразумевает, что выделенная память может быть доступна как массив char (в соответствии с вашим примером), и поэтому арифметика указателей хорошо определена.

...