Оператор косвенного обращения и указатели на массив - PullRequest
1 голос
/ 21 октября 2011

Кажется, что обычное определение оператора косвенности не применяется, когда оно используется в многомерных массивах:

int arr[10][10][10];

Если вы разыграете arr, вы получите тот же адрес:

(void*)arr == (void*)*arr && (void*)*arr == (void*)**arr

Это имеет смысл, хотя - многомерный массив - это просто непрерывная область памяти, где указатель указывает на начало памяти. Компилятор по существу игнорирует разыменования и просто вычисляет правильное смещение. Использование оператора косвенности, по-видимому, только сохраняет абстракцию многомерных массивов и обеспечивает его соответствие другим синтаксическим конструкциям языка.

Если вы делаете следующее:

int *** ptr = (int***) arr;

И разыменование ptr, вы увидите нормальное поведение разыменования, когда возвращается значение в местоположении, указанном указателем. Используя приведенное выше приведение, вы будете читать в неопределенную память, если разыменуете указатель более чем в два раза.

Мне просто интересно, почему это поведение не документировано в большем количестве мест - то есть, разница влияния оператора косвенности на указатели на массивы против указателей на указатели и указатели на значения?

1 Ответ

1 голос
/ 21 октября 2011

Во-первых, чтобы полностью понять это, вы должны понимать, что C не имеет многомерных массивов - у него есть массивы массивов. Итак, в вашем примере arr - это "массив из 10 массивов из 10 массивов по 10 дюймов" .

Во-вторых, по-другому ведет себя не оператор косвенного обращения, а странное поведение выражений с типом массива.

Если выражение с типом массива является , а не субъектом унарных & или sizeof операторов 1 , то оно оценивается как указатель на первый элемент этот массив.

Это означает, что в следующем выражении:

(void*)*arr == (void*)**arr

С левой стороны, arr вычисляет указатель на первый массив из 10 массивов по 10 дюймов в пределах arr (то есть &arr[0]). Затем разыменовывается для получения самого этого массива: первого подмассива в arr, arr[0]. Однако, поскольку arr[0] сам по себе является массивом, он заменяется указателем на это первый элемент, &arr[0][0].

С правой стороны, вышеупомянутое происходит с левой стороны, затем разыменовывается последний указатель, получая arr[0][0]. Это опять-таки массив, поэтому он наконец заменяется указателем на свой первый элемент, &arr[0][0][0].

Причина, по которой они равны (после преобразования в void *), заключается просто в том, что адрес массива arr[0][0] и адрес int arr[0][0][0] совпадают, так как последний является первым членом первого. Они также соответствуют адресам arr[0] и arr, поэтому у вас также есть:

(void *)&arr == (void *)arr;
(void *)arr == (void *)*arr;

.


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