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

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

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

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

Да, вы можете взять адрес один за концом массива, но вы не можете его разыменовать. Для вашего массива из 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 
  • Инициализация указателя в отдельной функции в C
  • Использование стрелки (->) в C
  • Почему я не могу обработать массив как указатель в C?
  • Что такое имя массива в c?
  • Разница между char * str = "STRING" и char str = "STRING"?
  • Как выровнять указатель в C
  • Параметр, проходящий в C - указатели, адреса, псевдонимы
  • Почему не указатели инициализируются с помощью NULL по умолчанию?
  • Как печатать переменные адреса в C?
  • Являются ли a, & a, a, a , & a и & a одинаковыми указателями?
  • Что такое тип данных uintptr_t
  • Давайте будем гением компьютера.