A variable has a number of distinct properties.
Given your variable definition, which I quote here
int num = 5;
its type is int
, its name is num
, it is initialised with a value of 5
, and its address (e.g. location in machine memory) is &num
.
If I was to define a second variable immediately after
int q = 5
then this variable would (like num
) have type int
, and value 5
, but a different name q
and a different address in memory &q
. Even though they have the same value, the addresses of num
and q
are different. That (among other things) ensures that assigning q = 6
does not change the value of num
.
It goes further. The pointer in your sample
int * p;
means that p
is a pointer to an int
. It has type int *
, so its value can be the address of an int
. So the assignment
p = num; //This results in an error
doesn't work, because p
has type int *
and num
has type int
. The two types are distinct, and an int
cannot be converted implicitly to an int *
, so the assignment is not allowed. They are different types. In the real world, the street address of a house is something different from a house, even if there is an association between them.
However your assignment
p = # //This does not
works, because p
is of type int *
and &num
is the address of an int
so also has type int *
.
However, with arrays, the rules are a little different.
int num[2] = {5, 10};
p = num; //This does not result in an error
p = # //This does
Firstly, num
is an array of two int
. It has name num
, but its type is int[2]
, and its value is actually based on the pair of int
s 5
and 10
.
When used in an expression, num
is converted to a pointer to its first element. So
p = num;
is equivalent to
p = &num[0];
The conversion of num
to &num[0]
is called an "array to pointer" conversion.
The second assignment you tried
p = # //This does
is different. In this case &num
is the address of the array num
, not the address of its first element. So &num
has type int (*)[2]
which (in C++) syntactically means "pointer to an array of two int
".
The type of p
is int *
(because that's how you defined it) whereas &num
gies a result with type int (*)[2]
. Those types are different, so the assignment is invalid.
If you want a variable that points to an array of two int
(as distinct from your p
which can point at the first element of an array of int
) then define
int num[2] = {5,10};
int (*q)[2]; // q has type int (*)[2]
q = num; // this will work
Then you can do, for example;
std::cout << (*q)[0] << ' ' << (*q)[1] << '\n';
to print the values 5
and 10
. This works because q
points at the array, *q
is (a reference to) the array num
, so (*q)[0]
and (*q)[1]
access num[0]
and num[1]
respectively.
Note that the parentheses ()
are critical in all of the above discussion. *q[0]
is actually (by rules of operator precedence and associativity) equivalent to *(q[0])
which is something quite different from (*q)[0]
. I'll leave working out what *(q[0])
is (or is not) an exercise.