Как разыменование работает для указателя на массив? - PullRequest
2 голосов
/ 23 мая 2019

Указатель на массив элементов при разыменовании возвращает адрес.Поскольку он содержит адрес первого элемента массива, разыменование должно возвращать значение.

int arr[] = { 3, 5, 6, 7, 9 }; 
int *p = arr; 
int (*ptr)[5] = &arr;     
printf("p = %p, ptr = %p\n", p, ptr); 
printf("*p = %d, *ptr = %p\n", *p, *ptr);

Вывод:

p = 0x7fff6ea72d10, ptr = 0x7fff6ea72d10

* p = 3, * ptr = 0x7fff6ea72d10

Почему * ptr возвращает базовый адрес массива, если он не возвращает значение по этому адресу ??

Ответы [ 5 ]

8 голосов
/ 23 мая 2019

Почему * ptr возвращает базовый адрес массива, не так ли? вернуть значение по этому адресу ??

(p3) За исключением случаев, когда это операнд оператора sizeof, оператора _Alignof или унарный оператор '&' или строковый литерал , используемый для инициализации массива, выражение с типом «массив типа» преобразуется в выражение с типом «указатель на тип» , которое указывает на начальный элемент объекта массива и не является lvalue. Стандарт C11 - 6.3.2.1 Другие операнды - L-значения, массивы и обозначения функций (p3)

int (*ptr)[5] = &arr;

ptr - это указатель на массив из int [5]. При разыменовании ptr вы получаете массив int[5]. Как получить доступ к массиву int[5]?

Правило 6.3.2.1 дает ответ:

"массив типа" преобразуется в выражение с типом "указатель на тип" , которое указывает на начальный элемент объекта массива ...

Теперь, если вы снова разыменовываете (например, **ptr), тогда вы получите значение 1-го элемента.

3 голосов
/ 23 мая 2019

Вопрос был

"Почему *ptr возвращает базовый адрес массива, не должен ли он возвращать значение по этому адресу?"

Он возвращает значение по этому адресу, которое массив arr.

Подумайте об очереди людей: вы можете указать на первого человека и сказать «этот человек там», или вы можете указать на того же человека и сказать «эта очередь там». В одном месте есть 2 вещей: человек и очередь. То же самое происходит с массивами: person * для этого "человека там" и person (*)[42] "для этой очереди из 42 человек". Если вы разыменуете указатель на очередь, вы получите очередь. Если вы берете первое из очереди, вы получаете человека.


Но , тогда сам массив будет уменьшаться до адреса до первого элемента, если он задан в качестве аргумента printf. Таким образом, здесь

int arr[] = { 3, 5, 6, 7, 9 }; 
int (*ptr)[5] = &arr;     

// undefined behaviour really, all pointers should be cast to void *
printf("%p %p %p %p", *ptr, &ptr[0], arr, &arr[0]);

все эти 4 выражения приведут к указателю на int, а значением является адрес первого элемента в массиве (адрес 3 в arr).

0 голосов
/ 23 мая 2019

Поведение, которое вы видите, является результатом интерпретации 'c' arr как указателя на ячейку памяти первого элемента. Указатель на массив &arr будет адресом самого массива в памяти, который также является адресом его первого элемента. В результате arr и &arr дают одинаковые значения. Попробуйте это:

printf("array = %p, &array = %p\n", arr, &arr);

Думал, что значения одинаковы, типы разные. arr - это переменная, &arr - указатель на переменную.

ptr отражает ту же картину. Его значение ptr = &arr делает его указателем на массив. Содержит адрес массива. *ptr возвращает сам массив, который в интерпретации 'c' является адресом первого элемента массива. В результате значения для ptr и *ptr такие же, как для &arr и arr.

Надеюсь, это прояснит (не мрачнее): -)

0 голосов
/ 23 мая 2019

Вот простое, менее техническое объяснение.

Как вы настраиваете p?= arr;

Как вы настраиваете ptr?= &arr;

Ваш вопрос на самом деле не имеет ничего общего с массивами.arr может быть буквально любого типа, и ответ будет таким же: & получает адрес arr, поэтому, чем бы ни был arr, ptr хранит свой адрес, в то время как p хранит arrсам.

Если вы сделаете *ptr, вы будете разыменовывать этот адрес и, таким образом, получите значение, равное p.

int arr = 3;
// clearly these are different!
int p = arr;
int* ptr = &arr;

Аналогично

int x = 3;
int* arr = &x;
// clearly these are different!
int* p = arr;
int** ptr = &arr;
// so of course they dereference differently
printf("*p = %d, *ptr = %p\n", *p, *ptr);
0 голосов
/ 23 мая 2019

Массивы являются указателями. Массивы не являются указателями, см. Комментарии ниже

Указатель на массив - это указатель, указывающий на указатель.Попробуйте дважды разыменовать ссылку, чтобы получить значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...