Щоб зрозуміти цей злом, спочатку потрібно зрозуміти різницю вказівника, тобто що відбувається, коли відняти два покажчики, що вказують на елементи одного масиву ?
Коли один покажчик віднімається від іншого, результатом є відстань (вимірюється в елементах масиву) між покажчиками. Отже, якщо p
вказує на a[i]
і q
вказує на a[j]
, то p - q
дорівнюєi - j
.
C11: 6.5.6 Оператори добавок (p9):
Коли віднімаються два покажчики , обидва повинні вказувати на елементи одного і того ж об’єкта масиву або один минулий останній елемент об’єкта масиву; результат - різниця підписів двох елементів масиву . [...].
Іншими словами, якщо вирази P
і Q
вказують відповідно на i
-ий-й j
елементи об’єкта масиву, вираз (P)-(Q)
має значення заi−j
умови, що значення вписується в об'єкт типу ptrdiff_t
.
Тепер я очікую, що вам відомо про перетворення імені масиву в покажчик, a
перетворює вказівник на перший елемент масиву a
. &a
- це адреса всього блоку пам'яті, тобто це адреса масиву a
. Малюнок нижче допоможе вам зрозуміти ( прочитайте цю відповідь для детального пояснення ):
Це допоможе вам зрозуміти, що чому a
і &a
має таку саму адресу, і як (&a)[i]
адреса i- го масиву (такого ж розміру, як і a
).
Отже, заява
return (&a)[n] - a;
еквівалентно
return (&a)[n] - (&a)[0];
і ця різниця дасть кількість елементів між покажчиками (&a)[n]
та (&a)[0]
, які є n
масивами кожного з n
int
елементів. Тому загальні елементи масиву n*n
= n
2 .
ПРИМІТКА:
C11: 6.5.6 Оператори добавок (p9):
Коли віднімаються два покажчики, обидва повинні вказувати на елементи одного і того ж об’єкта масиву або один минулий останній елемент об’єкта масиву ; результат - різниця підписів двох елементів масиву. Розмір результату визначається реалізацією , а його тип (тип підписаного цілого числа) ptrdiff_t
визначається у <stddef.h>
заголовку. Якщо результат не є представним в об'єкті цього типу, поведінка не визначена.
Оскільки (&a)[n]
ані вказівки на елементи того самого об’єкта масиву, ані один минулий останній елемент об’єкта масиву, (&a)[n] - a
не викликатиме визначеної поведінки .
Також зауважте, що краще змінити тип повернення функції p
на ptrdiff_t
.