Могу ли я взять адрес элемента "один конец прошлого" массива?

Возможный дубликат:
Возьмите адрес элемента массива "один за прошлым" через индекс: легальный по стандарту С++ или нет?

int array[10];

int* a = array + 10;   // well-defined
int* b = &array[10];   // not sure...

Является ли последняя строка действительной или нет?

Ответ 1

Да, вы можете взять адрес один за концом массива, но вы не можете его разыменовать. Для вашего массива из 10 элементов array+10 будет работать. Несколько раз утверждалось (комитетом, среди прочих), действительно ли &array[10] вызывает поведение undefined или нет (и если да, то действительно ли это должно). Суть в том, что, по крайней мере, в соответствии с действующими стандартами (как C, так и С++), он официально вызывает поведение undefined, но если есть один компилятор, для которого он фактически не работает, никто ни в одном из аргументов не имеет смог найти или процитировать его.

Изменить: на этот раз моя память была наполовину правильной - это был (часть) официальной Отчет о дефектах в комитет и, по крайней мере, некоторые члены комитета (например, Том Плум) считали, что формулировка была изменена, чтобы она не вызывала поведение undefined. OTOH, DR датируется 2000 годом, и статус по-прежнему "Редактирование", поэтому он может поставить вопрос о том, действительно ли он зафиксирован или когда-либо будет (я не просмотрел N3090/3092, чтобы выяснить).

В C99, однако, это явно не поведение undefined.

Ответ 2

Как указывали другие ответы, выражение array[10] эквивалентно *(array + 10), что, по-видимому, приведет к разыменованию undefined элемента непосредственно за конец массива. однако выражение &array[10] эквивалентно &*(array + 10), а стандарт C99 делает понятным (6.5.3.2 Операторы адреса и косвенности):

Унарный и оператор возвращает адрес своего операнда. Если операнд имеет тип типа '', результат имеет тип '' указатель на тип. Если операнд является результатом унарного оператора *, ни тот оператор, ни оператор и не оцениваются, и результат выглядит так, как если бы оба были опущены, за исключением того, что ограничения для операторов все еще применяются, а результат не является значением l. Аналогично, если операнд является результатом оператора [], ни оператор &, ни унарный *, который подразумевается [], не оцениваются, а результат выглядит так, как если бы оператор & был удален и оператор [] были заменены на оператор a +.

Итак, ничего undefined около &array[10] - не происходит никакой операции разыменования.

Ответ 3

array[10] эквивалентен *(array + 10) (а также эквивалентен 10[array]), поэтому &array[10] действует как удаление * из *(array+10). Любой достойный компилятор должен испускать один и тот же код (и такое же предупреждение).

Ответ 4

Нет. Это undefined. array[10] составляет *(array + 10). Другими словами, вы разыменовали неверный указатель.

Ответ 5

На самом деле это довольно простая задача.

Все, что вы делаете, это указатель math, в нем нет ничего недействительного. Если вы попытаетесь каким-то образом использовать полученные результирующие указатели, то зависит от того, имеет ли ваш процесс доступ к памяти, на которую указывает этот указатель, и если да, то какие у него права?

foo.cc:

#include <iostream>

using namespace std;
int main() {
        int array[10];
        int *a = array + 10;
        int *b = &array[10];
        int *c = &array[3000];

        cerr << "Pointers values are: " << a << " " << b << " " << c << endl;
        return 0;
}

Скомпилировать:

g++ -Werror -Wall foo.cc -o foo

должен выдавать предупреждения NO, поскольку массив int * b = & [10] действителен

Собственно, так же, как и последующая строка, добавленная мной, чтобы просто указать что-то о математике указателя.

не только скомпилируется, он будет работать без сбоев:

 ./foo
  Pointers are: 0x7fff1d356e68 0x7fff1d356e68 0x7fff1d359d20

В основном синтаксис массива foo [idx] - это сокращение и чистое представление математики указателя.

В случае некоторой путаницы в отношении c99, стандарт НЕ влияет на эту математику в любом случае и четко определен.

То же самое в C99:

#include <stdio.h>

int main() {
        int array[10];
        int *a = array + 10;
        int *b = &array[10];
        int *c = &array[3000];

        fprintf(stderr, "Pointers are: %p, %p, %p\n" , a , b , c );
        return 0;
}

Тогда:

gcc -std=c99 -Wall -Werror -o foo foo.c

./foo

Выходы:

Pointers are: 0x7fff2c7d22c8, 0x7fff2c7d22c8, 0x7fff2c7d5180