В вашем интересном вопросе есть два момента:
- Как работает работа с указателями?
- В чем разница между arr и & arr?
1: Как работает работа с указателями?
Попробуйте следующий код:
#include <stdio.h>
#include <inttypes.h>
int main(int argc, char **argv) {
int simpleInt= 10 ;
printf("Output 1 : %p %p \n", &simpleInt+1, &simpleInt); // 61FE20 and 61FE1C
printf("Output 2 : %lld \n", &simpleInt+1 - &simpleInt); // 1
printf("Output 3 : %lld\n", (uint64_t)(&simpleInt+1) - (uint64_t)(&simpleInt)); // 4
}
Выход 1: Очевидно, разница между двумя значениями указателя напечатана 4
Выход 2: Вы выполняете операцию на int *
. 1 добавляется к операнду типа int *
и после вычитания операнда типа int *
. С "int *
точки зрения" (если бы я мог так упростить это), добавляется только один. Таким образом, вывод равен 1.
Ouput 3: каждый операнд вычитания приводится к длинному длинному целому без знака. Таким образом, вычитание выполняется на целых числах, а не на указателях. Выходное значение равно 4, как и ожидалось.
2. В чем разница между arr и & arr?
Давайте посмотрим на следующий код
int arr[5] = {10, 20, 30, 40, 50};
printf("Output 1 : %p %p %p \n", arr, &arr, *(&arr) ); //Seems to be the same thing but NOT. int*, int*[5], int*, respectively
// printf("%lld\n", arr - &arr ); // compilation error : int * and int(*)[5]
printf("Output 2 : %lld\n", arr - *(&arr) );
//printf("%lld\n", &arr - *(&arr) ); // compilation error : int(*)[5] and int *
printf("Output 3 : %p %p %p \n", (arr + 1), (&arr + 1), *(&arr + 1) ); // +4, +20, +20
printf("Output 4 : %lld\n", *(&arr + 1) - arr);
printf("Output 5 : %lld\n", (uint64_t)(*(&arr + 1)) - (uint64_t)(arr));
Ouput 1: значения одинаковы, но не тип аргументов. И этот момент очень важен. Имя массива является указателем на его первый элемент. В вашем случае ваш массив - это массив int
, поэтому arr
- это указатель на int: int*
. &arr
- это адрес вашей переменной arr
, который представляет собой массив из 5 целых чисел. Таким образом, тип &arr
равен int(*)[5]
. И тип *(&arr)
равен int*
Выход 2: Некоторые строки дают ошибки компиляции из-за объяснения выше. И вы можете выполнять операции с одним и тем же типом указателя: arr
и *(&arr)
Выход 3: В зависимости от того, какой тип указателя увеличивается, получается +4 или +20. +20, потому что 1 добавлен к операнду типа int(*)[5]
: 5 * 4 (sizeof int
= 4)
Выход 4 и 5: Как и в первой точке (операция с указателем), ваш выполняем вычитание с int*
в качестве операнда