C получение размера массива - PullRequest
1 голос
/ 12 апреля 2020

код:

int arr[5] = {10, 20, 30, 40, 50};

printf("%lu %lu\n", *(&arr + 1), arr); // 6422036 6422016
printf("%lu\n", *(&arr + 1) - arr);    // 5

Почему второй printf печатает 5 вместо 20?

Ответы [ 2 ]

0 голосов
/ 12 апреля 2020

В вашем интересном вопросе есть два момента:

  1. Как работает работа с указателями?
  2. В чем разница между 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* в качестве операнда

0 голосов
/ 12 апреля 2020

Почему второй printf печатает 5 вместо 20?

Код живет по краю.

&arr - это адрес массива, поэтому + 1 - это адрес массива next : 5 int позже. Пока это хорошо.

*(&arr + 1) разыменовывает этот адрес. Таким образом, мы получаем этот следующий массив. Не очень хорошо @ RobertS поддерживает Monica Cellio . Массив, переданный функции ... типа printf(), преобразуется в адрес первого элемента, а int *.

*(&arr + 1) - arr вычитает два указателя одного типа int *, которые равны 5 int друг от друга, что приводит к разнице 5 типа intptr_t. Напомним, что вычитание указателя является разностью числа ссылочных типов (в данном случае int), а не разностью значений указателя. 5 не 20 .

Код пытается напечатать intptr_t как unsigned long с "%lu", что может работать, может не сработать (UB). Не так хорошо, как хотелось бы. Лучше использовать "%td".

printf("%td\n", *(&arr + 1) - arr); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...