Эта строка наиболее важна:
size = *(&a + 1) - a;
Как видите, сначала она берет адрес a
и добавляет к нему один.Затем он разыменовывает этот указатель и вычитает из него исходное значение a
.
Арифметика указателя в C заставляет его возвращать количество элементов в массиве, или 5
.Добавление одного и &a
является указателем на следующий массив через 5 int
с после a
.После этого этот код разыменовывает результирующий указатель и вычитает a
(тип массива, который распался на указатель) из него, давая количество элементов в массиве.
Подробно о том, как работает арифметика указателей:
Скажем, у вас есть указатель xyz
, который указывает на тип int
и содержит значение (int *)160
.Когда вы вычитаете любое число из xyz
, C указывает, что фактическая сумма, вычтенная из xyz
, равна числу, умноженному на размер типа, на который оно указывает.Например, если вы вычли 5
из xyz
, значение xyz
будет равно xyz - (sizeof(*xyz) * 5)
, если арифметика указателя не будет применена.
Поскольку a
- это массив 5
int
типов, полученное значение будет 5. Однако, это не будет работать с указателем, только с массивом.Если вы попробуете это с указателем, результат всегда будет 1
.
Вот небольшой пример, который показывает адреса и как это не определено.В левой части отображаются адреса:
a + 0 | [a[0]] | &a points to this
a + 1 | [a[1]]
a + 2 | [a[2]]
a + 3 | [a[3]]
a + 4 | [a[4]] | end of array
a + 5 | [a[5]] | &a+1 points to this; accessing past array when dereferenced
Это означает, что код вычитает a
из &a[5]
(или a+5
), давая 5
.
Обратите внимание, что это неопределенное поведение, и его не следует использовать ни при каких обстоятельствах.Не ожидайте, что такое поведение будет одинаковым на всех платформах, и не используйте его в производственных программах.