Как работает sizeof с разыменованием указателя на массив?

9

Здесь у меня есть указатель ptrна массив arrиз 4 целых чисел. ptrуказывает на весь массив. ptr[0]или *ptrуказывает на первый элемент массива, поэтому добавление 1 к ptr[0]дает адрес второго элемента массива.

Я не могу понять, почему использование sizeof(ptr[0])дает размер всего массива, 16 байтов, а не размер только первого элемента, 4 байта, (как ptr[0]указывает на первый элемент в массиве).

int arr[4] = {0, 1, 2, 3};
int (*ptr)[4] = &arr;
printf("%zd", sizeof(ptr[0])); //output is 16
Абд-Эльрахман Мухаммед
источник
Не должно быть второй строки int *ptr = arr;? Это указало бы на начало (первый элемент) массива, что эквивалентно &arr[0].
Андреас Венцель
1
@AndreasWenzel Не должно быть второй строки int *ptr = arr;? Вообще-то, нет. int (*ptr)[4]создает ptrкак указатель на полный массив из четырех intзначений. Подобный синтаксис указателя необходим для динамического выделения многомерных массивов. «2-мерные массивы», созданные с помощью вложенных malloc()циклов и ошибочно описанные как многомерные массивы, на самом деле являются 1-мерными массивами указателей на несколько 1-мерных массивов. См. Stackoverflow.com/questions/42094465/…
Эндрю Хенле

Ответы:

6

OP: ptr[0]указывает на первый элемент в массиве.

Типа путаницы. ptr[0]это массив.

ptr является указателем на массив 4 междунар . Вроде
ptr[0]как *ptrзадерживает указатель на массив .
sizeof(ptr[0])это размер массива.


С sizeof(ptr[0]), ptr[0]не вызывает преобразования «выражение с типом« указатель на тип », который указывает на начальный элемент объекта массива». (c11dr §6.3.2.1 3). С sizeof, ptr[0]это массив.

Chux - Восстановить Монику
источник
1
@ Abd-ElrahmanMohamed Согласен "Но ptr [0] [0] является целым числом, а не целым числом". «ptr [0] является адресом первого элемента в массиве» не соответствует истине.
chux - Восстановить Монику
1
@ Abd-ElrahmanMohamed Да, значения одинаковы, но типы разные. ptr [0] имеет тип массива и &ptr[0][0]имеет int *тип
Green Tree
1
@chux ptr[0](неявно преобразуется в int *) будет вычислять адрес первого элемента int.
Зеленое дерево
1
@chux о sizeof - верно, я неправильно понял контекст того, что вы сказали
Green Tree
1
@ Abd-ElrahmanMohamed Это не так. printf("someforamt", ptr[0] , ptr[0]+1)делает что-то другое, чем sizeof(ptr[0]). В ptr[0]первом случае происходит неявное преобразование. С sizeof(ptr[0]), ptr[0]не делает.
chux - Восстановить Монику
5

ptrздесь тип pointer to an array of 4 int elementsи тип массива имеет размер 16 на вашей платформе (sizeof (int) * (число элементов)).

Я не могу понять, почему использование sizeof (ptr [0]) дает размер всего массива 16 байтов, а не размер только первого элемента 4 байта

потому что система типов C имеет типы массивов. Вот так arrи *ptrесть. То, что вы заявляете, что у вас есть. Чтобы получить sizeof здесь, вы должны sizeof (ptr [0] [0]) - где ptr [0] вычисляется как массив.

Зеленое дерево
источник
2

у int (*ptr)[4] = &arr ;вас есть указатель на массив из четырех целых чисел и указывающий на обр.

ptrтеперь указывает на arr, как двойной указатель. Мы можем получить доступ к элементам с arrпомощью ptr[0][x]которых xможно было бы 0с 4.

Так sizeof(ptr[0])же, какsizeof(arr)

rsonx
источник
2

По определению, ptr[0]это то же самое, *(ptr + 0)что, в свою очередь, то же самое, что и *ptr. Кроме того, ptrинициализируется &arr, так *ptrэто *&arrи просто arr. Следует отметить , что промежуточное хранение &arrв ptrвовсе не выполняет никакого распада массива, так что эквивалентность сохраняется и никакой информации типа не теряется.

Обратите внимание, что все это вычисляется во время компиляции, просто чтобы избежать этой дополнительной ошибки.

Ульрих Экхардт
источник