Разыменование 3-мерного массива

#arrays #c #pointers #dereference

#массивы #c #указатели #разыменование

Вопрос:

 #include "stdio.h"


int main(){

int D[2][3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};


printf("D: %pn", D);
printf("*(0x0061FEC8): %dn", *((int *)(0x0061FEC8)));
printf("*D: %pn", *D);

    return 0;
}
  

Результат приведенного выше кода:

 D: 0061FEC8
*(0x0061FEC8): 1
*D: 0061FEC8
  

p.s: я получил адрес 0x0061FEC8, запустив код несколько раз, и увидел, что он не меняется. Поскольку разыменование целого числа запрещено, я также преобразовал его в целочисленный указатель.

Хорошо, я прочитал в нескольких источниках, что за двумя исключениями операторов amp; и sizeof имена многомерных массивов распадаются на указатели на первый элемент этого смежного блока памяти. Итак, если имя 3D-массива D распадается на указатель на первый элемент, почему выходные данные 2-й и 3-й строк разные?D должен распадаться на адрес 0x0061FEC8, и разыменование этого адреса, на мой взгляд, должно давать значение 1. Однако он снова печатает адрес.

Комментарии:

1. Какова цель выполнения *((int *)(0x0061FEC8)) ? Просто не делайте ничего подобного!

2.С ASLR помощью (рандомизация расположения адресного пространства) вы не можете гарантировать фиксированный адрес [поэтому не делайте этого в реальном коде]. Но третий printf должен использовать %d , а не %p

3. Если D бы это был одномерный массив, то разыменование является указателем на первый целочисленный элемент. Но это 3D-массив, и его разыменование указывает на первый из двух его 2D-массивов.

4. @CraigEstey замена %p на %d просто выводит десятичный эквивалент адреса

5. @muyustan Хм, да. Он D разыменован, но я разнесен на D 3D. Вопрос OP заключался в том, почему 2-й и 3-й были разными, а формат был другим. Я предположил, что OP получил правильный дереф, и только формат был неправильным

Ответ №1:

Когда вы это делаете *((int *)(0x0061FEC8)) , вы рассматриваете адрес в этом местоположении как указатель на первые элементы одномерного массива. Когда вы разыменовываете этот указатель, вы получаете значение в этом местоположении.

Но когда вы это делаете *D , это то же D[0] самое, что и, который имеет тип int [3][3] . Он будет распадаться на указатель на D[0][0] , который имеет тип int (*)[3] . Т.е. *D не является значением.

Итак, два выражения выполняют две совершенно разные вещи. Один (первый) неверен, а второй правильный.