Это неудачный пример для обучения, поскольку он подразумевает, что можно делать некоторые неправильные вещи, которые часто работают на практике.
Технически правильный ответ заключается в том, что программа имеет неопределенное поведение, поэтому любой результат возможенвключая печать -10, печать другого числа, печать чего-то другого или вообще ничего, сбой запуска, сбой и / или выполнение чего-то совершенно не связанного.
Неопределенное поведение возникает в результате оценки подвыражения array -2
.array
распадается из своего типа массива на указатель на первый элемент.array -2
будет указывать на элемент, который до этого стоит на две позиции, но такого элемента нет (и это не специальное правило «один за другим»), поэтому оценка этого является проблемой независимо от того, в каком контекстепоявляется в.
(C11 6.5.6 / 8 говорит)
Когда выражение, имеющее целочисленный тип, добавляется или вычитается из указателя, .... Если обаоперанд указателя и результат указывают на элементы одного и того же объекта массива или одного элемента после последнего элемента объекта массива, оценка не должна вызывать переполнение;в противном случае поведение не определено.
Теперь технически неверный ответ, который, вероятно, ищет инструктор, - это то, что на самом деле происходит в большинстве реализаций:
Даже если array -2
вне фактического массива он оценивает некоторый адрес, который составляет 2*sizeof(int)
байт перед адресом, где начинаются данные массива.Недопустимо разыменовывать этот адрес, поскольку мы не знаем, что там действительно есть int
, но мы не собираемся.
Глядя на большее выражение -2[array -2]
, оператор []
имеет более высокий приоритет, чем унарный оператор -
, поэтому он означает -(2[array -2])
, а не (-2)[array -2]
.A[B]
определяется так же, как *((A)+(B))
.Обычно A
является значением указателя и B
является целочисленным значением, но также допустимо использовать их в обратном порядке, как мы делаем здесь.Таким образом, они эквивалентны:
-2[array -2]
-(2[array -2])
-(*(2 + (array - 2)))
-(*(array))
Последний шаг действует так, как мы и ожидали: добавление двух к значению адреса array - 2
составляет 2*sizeof(int)
байт после этого значения, что возвращает нас к адресупервый элемент массива.Так что *(array)
разыменовывает этот адрес, давая 10, а -(*(array))
отменяет это значение, давая -10.Программа печатает -10.
Вы никогда не должны рассчитывать на такие вещи, даже если вы заметили, что это "работает" в вашей системе и компиляторе.Поскольку язык ничего не гарантирует относительно того, что произойдет, код может не работать, если вы сделаете небольшие изменения, которые кажутся не связанными, или в другой системе, в другом компиляторе, в другой версии того же компилятора или с использованиемта же система и компилятор в другой день.