Почему этот указатель на выражение массива работает - PullRequest
1 голос
/ 17 апреля 2020

Я не могу понять, почему этот код работает таким образом. Я знаю, что ptr является указателем на массив int и указывает на вторую «строку» arr.

int arr[][2] = { {1}, 2, 3};
int (*ptr)[2] = arr + 1;
cout << (**arr)[*ptr];

Он печатает 3, что равно arr[1][1], но **arr равно 1 и *ptr является адресом памяти arr[1][0].
Почему (**arr)[*ptr] возвращает 3? Я что-то здесь упускаю?

1 Ответ

2 голосов
/ 17 апреля 2020

Это объявление

int arr[][2] = { {1}, 2, 3};

объявляет массив из двух элементов типа int[2].

Это выражение

(**arr)

дает целочисленное значение 1.

Это объявление

int (*ptr)[2] = arr + 1;

объявляет указатель на второй элемент массива обр. Так что * ptr возвращает эту вторую «строку» массива arr. Используя в таких выражениях

(**arr)[*ptr]

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

Итак, у вас есть выражение вроде

int[int *]

или

i[p]

, где i - целочисленное значение, а p - указатель.

Это эквивалентно

int *[int]

или

p[i]

, поскольку согласно C ++ Standard (или C Standard) оба оцениваются как

*( p + i )

Так как ** arr равен 1, а выражение * ptr указывает на первый элемент второй строки, а затем на результат является вторым элементом второй строки, равным 3.

Из стандарта C ++ 17 (5.2.1 подписка)

1 Постфиксное выражение, за которым следует выражение в квадратных скобках: постфиксное выражение. Одно из выражений должно иметь тип «массив из T» или «указатель на T», а другое должно иметь перечисление с незаданной областью или целочисленный тип. Результат имеет тип «T». Тип «T» должен быть полностью определенным типом объекта.64 Выражение E1 [E2] идентично (по определению) * ((E1) + (E2)) [Примечание: см. 5.3 и 5.7 для деталей * и + и 8.3.4 для деталей массивов. - примечание конца], за исключением того, что в случае операнда массива, результатом является lvalue, если этот операнд является lvalue и xvalue в противном случае.

То есть, если у вас есть такой массив

T a[N];

где T - это некоторый спецификатор типа, когда выражение

a[i]

эквивалентно

i[a]

при условии, что i представляет выражение постфикса.

Вот демонстрационная программа.

#include <iostream>

int main() 
{
    int a[] = { 1, 2, 3, 4, 5 };

    const size_t N = sizeof( a ) / sizeof( *a );

    size_t i = 0;

    while ( i != N ) std::cout << i++[a] << ' ';
    std::cout << '\n';

    return 0;
}

Его вывод

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