#include "stdio.h"
int main(void)
{
int a[3][2] = {{10,2}, {2,3}, {3,4}};
printf("%p
", a[0]);
printf("%p
", (int *)a);
printf("%p
", *a);
printf("%p
", a);
printf("%p
", &(a[0][0]));
return 0;
}
Код выдает одно и то же число...
Особенно поражает то, что равны a и *a.
Что происходит?
И еще когда смотрю на *(int *)a, то получаю 10...
Ответ
Вас не должно удивлять равенство a и *a в данном контексте. Нечего удивительного в этом нет. В языке С "двумерный массив" - это просто обычный одномерный массив, элементами которого тоже являются одномерные массивы.
Одномерный массив, скажем, double d[10] - это просто плоский непрерывный компактный блок памяти, размера 10 * sizeof(double), состоящий из десяти плотно лежащих друг за другом элементов типа double. При этом адрес всего массива &d численно совпадает с адресом его нулевого элемента &d[0], ибо "начинаются" они в одной и той же точке памяти. Ситуация полностью аналогична равенству указателей вот в таком вот примере
struct S { int a; } s;
printf("%p %p
", (void *) &s, (void *) &s.a);
// Оба указателя совпадают численно
Адрес всего объекта struct-типа численно совпадает с адресом самого первого поля внутри этого объекта. Совершенно аналогичным образом адрес всего массива численно совпадает с адресом самого первого (нулевого) элемента этого массива.
При этом в языке С выражение d типа "массив double [10]" в большинстве контекстов (не во всех) неявно приводится к типу double * - указателю, указывающему на нулевой элемент массива. Т.е. в большинстве контекстов выражение d ведет себя эквивалентно выражению &d[0], т.е. массив внешне ведет себя как указатель. Это явление называют array type decay. (Именно по этой причине массивы в С часто путают с указателями, хотя на самом деле это разные типы и никаких указателей в массивах нет.)
Все это немедленно применимо и к двумерным массивам (и многомерным массивам), ибо, как сказано выше, в языке С "двумерный массив" - это рекурсивная по своему устройству структура: это просто одномерный массив, элементами которого являются одномерные массивы. Вышеупомянутое явление array type decay работает неизменным образом на любом уровне этой рекурсии.
Выше выражение a изначально имеет тип int [3][2], но в данном контексте неявно приводится к типу "указатель на нулевой элемент массива a". Этот указатель имеет тип int (*)[2] и указывает на подмассив a[0] типа int [2] в составе a
Выражение *a изначально имеет тип int [2] - это подмассив a[0] в составе a, но в данном контексте *a неявно приводится к типу "указатель на нулевой элемент массива a[0]". Это указатель типа int *, который указывает на самый первый int в составе подмассива a[0], т.е. на a[0][0]
И сам a, и a[0], и a[0][0] начинаются в одной и той же точке памяти, по каковой причине числовые представления этих указателей совпадают
printf("%p %p %p
", (void *) &a, (void *) a, (void *) *a);
// Все три указателя совпадают численно
Комментариев нет:
Отправить комментарий