Переменная имеет ряд различных свойств.
Учитывая ваше определение переменной, которое я цитирую здесь
int num = 5;
его тип int
, его имя num
, оно инициализируется значением 5
, а его адрес (например, расположение в памяти машины) равен &num
.
Если бы я должен был определить вторую переменную сразу после
int q = 5
тогда эта переменная (например, num
) будет иметь тип int
и значение 5
, но с другим именем q
и другим адресом в памяти &q
. Даже если они имеют одинаковое значение, адреса num
и q
различны. Это (помимо всего прочего) гарантирует, что присвоение q = 6
не изменит значения num
.
Это идет дальше. Указатель в вашем образце
int * p;
означает, что p
является указателем на int
. Он имеет тип int *
, поэтому его значением может быть адрес int
. Итак, назначение
p = num; //This results in an error
не работает, потому что p
имеет тип int *
, а num
имеет тип int
. Два типа различны, и int
не может быть неявно преобразован в int *
, поэтому назначение не допускается. Они разных типов. В реальном мире адрес улицы дома отличается от дома, даже если между ними есть связь.
Однако ваше назначение
p = # //This does not
работает, потому что p
имеет тип int *
, а &num
является адресом int
, поэтому также имеет тип int *
.
Однако с массивами правила немного отличаются.
int num[2] = {5, 10};
p = num; //This does not result in an error
p = # //This does
Во-первых, num
- это массив из двух int
. У него есть имя num
, но его тип int[2]
, и его значение фактически основано на паре int
s 5
и 10
.
При использовании в выражении num
преобразуется в указатель на его первый элемент. Так
p = num;
эквивалентно
p = &num[0];
Преобразование num
в &num[0]
называется преобразованием «массив в указатель».
Второе задание, которое вы пробовали
p = # //This does
отличается. В этом случае &num
- это адрес массива num
, а не адрес его первого элемента. Таким образом, &num
имеет тип int (*)[2]
, который (в C ++) синтаксически означает «указатель на массив из двух int
».
Тип p
- int *
(потому что именно так вы его определили), тогда как &num
дает результат с типом int (*)[2]
. Эти типы различны, поэтому назначение недопустимо.
Если вам нужна переменная, которая указывает на массив из двух int
(в отличие от вашего p
, который может указывать на первый элемент массива int
), тогда определите
int num[2] = {5,10};
int (*q)[2]; // q has type int (*)[2]
q = num; // this will work
Тогда вы можете сделать, например;
std::cout << (*q)[0] << ' ' << (*q)[1] << '\n';
для печати значений 5
и 10
. Это работает, потому что q
указывает на массив, *q
является (ссылкой) на массив num
, поэтому (*q)[0]
и (*q)[1]
обращаются к num[0]
и num[1]
соответственно.
Обратите внимание, что круглые скобки ()
имеют решающее значение во всем приведенном выше обсуждении. *q[0]
на самом деле (по правилам приоритета операторов и ассоциативности) эквивалентно *(q[0])
, что весьма отличается от (*q)[0]
. Я оставлю работу над тем, что *(q[0])
является (или не является) упражнением.