Pointer to pointer clarification
I was following this tutorial about how does a pointer to a pointer work.
Let me quote the relevant passage:
int i = 5, j = 6, k = 7; int *ip1 = &i, *ip2 = &j;
Now we can set
int **ipp = &ip1;
and
ipp
points toip1
which points toi
.*ipp
isip1
, and**ipp
isi
, or 5. We can illustrate the situation, with our familiar box-and-arrow notation, like this:If then we say
*ipp = ip2;
we've changed the pointer pointed to by
ipp
(that is,ip1
) to contain a copy ofip2
, so that it (ip1
) now points atj
:
My question is: Why in the second picture, is ipp
still pointing to ip1
but not ip2
?
Forget for a second about the pointing analogy. What a pointer really contains is a memory address. The &
is the "address of" operator - i.e. it returns the address in memory of an object. The *
operator gives you the object a pointer refers to, i.e. given a pointer containing an address, it returns the object at that memory address. So when you do *ipp = ip2
, what you are doing is *ipp
get the object at the address held in ipp
which is ip1
and then assign to ip1
the value stored in ip2
, which is the address of j
.
Simply&
--> Address of*
--> Value at
Because you changed the value pointed to by ipp
not the value of ipp
. So, ipp
still points to ip1
(the value of ipp
), ip1
's value is now the same as ip2
's value, so they both point to j
.
This:
*ipp = ip2;
is the same as:
ip1 = ip2;
Like most beginner questions in the C tag, this question can be answered by going back to first principles:
- A pointer is a kind of value.
- A variable contains a value.
- The
&
operator turns a variable into a pointer. - The
*
operator turns a pointer into a variable.
(Technically I should say "lvalue" instead of "variable", but I feel it is more clear to describe mutable storage locations as "variables".)
So we have variables:
int i = 5, j = 6;
int *ip1 = &i, *ip2 = &j;
Variable ip1
contains a pointer. The &
operator turns i
into a pointer and that pointer value is assigned to ip1
. So ip1
contains a pointer to i
.
Variable ip2
contains a pointer. The &
operator turns j
into a pointer and that pointer is assigned to ip2
. So ip2
contains a pointer to j
.
int **ipp = &ip1;
Variable ipp
contains a pointer. The &
operator turns variable ip1
into a pointer and that pointer value is assigned to ipp
. So ipp
contains a pointer to ip1
.
Let's sum up the story so far:
-
i
contains 5 -
j
contains 6 -
ip1
contains "pointer toi
" -
ip2
contains "pointer toj
" -
ipp
contains "pointer toip1
"
Now we say
*ipp = ip2;
The *
operator turns a pointer back into a variable. We fetch the value of ipp
, which is "pointer to ip1
and turn it into a variable. What variable? ip1
of course!
Therefore this is simply another way of saying
ip1 = ip2;
So we fetch the value of ip2
. What is it? "pointer to j
". We assign that pointer value to ip1
, so ip1
is now "pointer to j
"
We only changed one thing: the value of ip1
:
-
i
contains 5 -
j
contains 6 -
ip1
contains "pointer toj
" -
ip2
contains "pointer toj
" -
ipp
contains "pointer toip1
"
Why does
ipp
still point toip1
and notip2
?
A variable changes when you assign to it. Count the assignments; there cannot be more changes to variables than there are assignments! You start by assigning to i
, j
, ip1
, ip2
and ipp
. You then assign to *ipp
, which as we've seen means the same as "assign to ip1
". Since you didn't assign to ipp
a second time, it didn't change!
If you wanted to change ipp
then you'll have to actually assign to ipp
:
ipp = &ip2;
for instance.
hope this piece of code can help.
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
int i = 5, j = 6, k = 7;
int *ip1 = &i, *ip2 = &j;
int** ipp = &ip1;
printf("address of value i: %p\n", &i);
printf("address of value j: %p\n", &j);
printf("value ip1: %p\n", ip1);
printf("value ip2: %p\n", ip2);
printf("value ipp: %p\n", ipp);
printf("address value of ipp: %p\n", *ipp);
printf("value of address value of ipp: %d\n", **ipp);
*ipp = ip2;
printf("value ipp: %p\n", ipp);
printf("address value of ipp: %p\n", *ipp);
printf("value of address value of ipp: %d\n", **ipp);
}
it outputs: