Мне кажется, я понимаю, как обычные переменные и указатели представлены в памяти, если вы используете C.
Например, легко понять, что указатель Ptr будет иметь адрес, а его значение будет быть другим адресом, то есть пространством в памяти, на которое он указывает. Следующий код:
int main(){
int x = 10;
int *Ptr;
Ptr = &x;
return 0;
}
Будет иметь следующее представление в памяти:
+---------------------+-------------+---------+
| Variable Name | Address | Value |
+---------------------+-------------+---------+
| x | 3342 | 10 |
+---------------------+-------------+---------+
| Ptr | 5466 | 3342 |
+---------------------+-------------+---------+
Однако мне трудно понять, как массивы представлены в памяти. Например, код:
int main(){
int x[5];
x[0]=12;
x[1]=13;
x[2]=14;
printf("%p\n",(void*)x);
printf("%p\n",(void*)&x);
return 0;
}
выводит один и тот же адрес дважды (для простоты 10568). Это означает, что x == & x. Тем не менее, * x (или x [0] в обозначении массива) равно 12, * (x + 1) (или x [1] в обозначении массива) равно 13 и так далее. Как это можно представить? Один из способов может быть таким:
+---------------------+-------------+----------+----------------------+
| Variable Name | Address | Value | Value IF array |
+---------------------+-------------+----------+----------------------+
| x | 10568 | 10568 | 12 |
+---------------------+-------------+----------+----------------------+
| | 10572 | | 13 |
+---------------------+-------------+----------+----------------------+
| | 10576 | | 14 |
+---------------------+-------------+----------+----------------------+
| | 10580 | | trash |
+---------------------+-------------+----------+----------------------+
| | 10584 | | trash |
+---------------------+-------------+----------+----------------------+
Это близко к тому, что происходит, или полностью отключено?
Массив - это блок смежных объектов без пробелов между ними. Это означает, что x
в вашем втором примере представлена в памяти как:
+---------------------+-------------+---------+
| Variable Name | Address | Value |
+---------------------+-------------+---------+
| x | 10568 | 12 |
| | +---------+
| | | 13 |
| | +---------+
| | | 14 |
| | +---------+
| | | ?? |
| | +---------+
| | | ?? |
+---------------------+-------------+---------+
То есть, x
имеет размер пять int
и имеет один адрес.
Странная часть массива не в том, как они хранятся, а в том, как они оцениваются в выражениях. Если вы используете имя массива где-то, что оно не является объектом унарных операторов &
или sizeof
, оно вычисляется по адресу его первого члена.
То есть, если вы просто напишите x
, вы получите значение 10568 с типом int *
.
Если, с другой стороны, вы пишете &x
, то специальное правило не применяется - поэтому оператор &
работает как обычно, что означает, что он выбирает адрес массива. В этом примере это будет значение 10568 с типом int (*)[5]
.
Причина, по которой x == &x
состоит в том, что адрес первого члена массива обязательно равен адресу самого массива, поскольку массив начинается с его первого члена.
Массив C - это просто блок памяти, который имеет последовательные значения одинакового размера. Когда вы вызываете malloc (), он просто предоставляет вам блок памяти. foo[5]
совпадает с *(foo + 5)
.
Пример - foo.c:
#include <stdio.h>
int main(void)
{
int foo[5];
printf("&foo[0]: %tx\n", &foo[0]);
printf("foo: %tx\n\n", foo);
printf("&foo[3]: %tx\n", &foo[3]);
printf("foo: %tx\n", foo + 3);
}
Вывод:
$ ./foo
&foo[0]: 5fbff5a4
foo: 5fbff5a4
&foo[3]: 5fbff5b0
foo: 5fbff5b0
int x [] выдает тот же результат, что и int * x;
это просто указатель
, поэтому обозначения x [i] и * (x + i) ) дают тот же результат.