Могу ли я взять адрес элемента «один конец прошлого» массива?
Возможный дубликат:
Возьмите адрес элемента массива «один конец прошлого» через индекс: легальный по стандарту C ++ или нет?
int array[10]; int* a = array + 10; // well-defined int* b = &array[10]; // not sure...
Является ли последняя строка действительной или нет?
- Это неуказанное поведение для сравнения указателей с разными массивами для равенства?
- Преобразование указателя в указатель между производными и базовыми classами?
- Безопасно ли удалить указатель NULL?
- Указатель на вектор
- Возrotation массива с использованием C
- Указатель против ссылки
- Является ли хорошей практикой освобождение NULL-указателя в C?
- Причина, почему бы не иметь макрос DELETE для C ++
- Функции хранилища C # в словаре
- Указатели в c ++ после удаления
- Передача 2D-массива функции C ++
- Что происходит, когда вы удаляете указатель дважды или больше на C ++?
- Неинициализированные указатели в коде
Да, вы можете взять адрес один за концом массива, но вы не можете его разыменовать. Для вашего массива из 10 элементов будет работать array+10
. Несколько раз (по мнению комитета) несколько раз утверждалось, действительно ли &array[10]
вызывает неопределенное поведение или нет (и если да, то действительно ли это должно). Суть в том, что, по крайней мере, согласно действующим стандартам (как C, так и C ++), это официально вызывает неопределенное поведение, но если есть один компилятор, для которого он фактически не работает, никому в любом из аргументов не удалось найти или процитировать его.
Изменить: на этот раз моя память была наполовину правильной – это (часть) официального отчета о дефектах для комитета, и по крайней мере некоторые члены комитета (например, Том Плум) считали, что формулировка была изменена, чтобы она не вызывала неопределенного поведения , OTOH, DR датируется 2000 годом, и статус по-прежнему «Редактирование», поэтому можно сомневаться, действительно ли он зафиксирован или когда-либо будет (я не просмотрел N3090 / 3092, чтобы выяснить).
Однако в C99 это явно не неопределенное поведение.
Как указывали другие ответы, array[10]
выражений array[10]
эквивалентен *(array + 10)
, что, по-видимому, приведет к неопределенному разыменованию элемента непосредственно за конец массива. однако выражение &array[10]
эквивалентно &*(array + 10)
, а стандарт C99 делает понятным (6.5.3.2 Операторы адреса и косвенности):
Унарный оператор & возвращает адрес своего операнда. Если операнд имеет тип ” type ”, результат имеет тип ” указатель на тип ”. Если операнд является результатом унарного
*
оператора, ни этот оператор, ни оператор & не оцениваются, и результат, как если бы оба были опущены, за исключением того, что ограничения для операторов все еще применяются, а результат не является значением l. Аналогично, если операнд является результатом оператора[]
, ни оператор&
ни унарный*
который подразумевается[]
не оцениваются, а результат выглядит так, как если бы оператор&
был удален, а оператор[]
был изменен на a +.
Итак, нет ничего неопределенного в &array[10]
– нет никакой операции разыменования, которая имеет место.
array[10]
эквивалентен *(array + 10)
(а также эквивалентен 10[array]
), поэтому &array[10]
действует как удаление *
from *(array+10)
. Любой достойный компилятор должен испускать один и тот же код (и такое же предупреждение).
Нет. Это неопределенно. array[10]
составляет *(array + 10)
. Другими словами, вы разыменовали неверный указатель.
На самом деле это довольно простая задача.
Все, что вы делаете, это указательная математика, в ней нет ничего недействительного. Если вы попытаетесь каким-то образом использовать полученные результирующие указатели, то зависит от того, имеет ли ваш процесс доступ к памяти, на которую указывает этот указатель, и если да, то каковы разрешения на него?
foo.cc:
#include 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 = & array [10]
На самом деле, это и есть последующая строка, добавленная мной, чтобы просто указать что-то о математике указателя.
не только скомпилирует, он будет работать без сучка и задоринки:
./foo Pointers are: 0x7fff1d356e68 0x7fff1d356e68 0x7fff1d359d20
В основном синтаксис массива foo [idx] - это сокращенное и чистое представление математики указателя.
В случае некоторой путаницы в отношении c99, стандарт НЕ влияет на эту математику в любом случае и четко определен.
То же самое в C99:
#include 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