#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
не является значением.
Итак, два выражения выполняют две совершенно разные вещи. Один (первый) неверен, а второй правильный.