Могу ли я взять адрес элемента "один конец прошлого" массива?
Возможный дубликат:
Возьмите адрес элемента массива "один за прошлым" через индекс: легальный по стандарту С++ или нет?
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