I have gotten stuck on modifying pointers of pointers. The problem is that I don't understand why my code works. What I am trying to do is modify where a pointer-to-pointer points to in a function. Then accessing that value in my main function. I tried quite a few attempts and this is the only way I got it to work.
#include <iostream>
using namespace std;
void changePP(int **ppint) {
int *n = new int;
*n = 9; //just a value for demonstration purposes
*ppint = n; //THE LINE IN QUESTION
delete n;
}
int main() {
int **ppint = NULL;
int *p = new int;
*p = 4; //another value for demonstrating
ppint = &p;
cout << **ppint << endl;
changePP(ppint);
cout << **ppint << endl;
}
So, the output is 4 and then a 9 on seperate lines. However, I am not sure about the line *ppint = n
in the code. Why do I have to use the *
to change where ppint points to in the changePP function but not in the main? Also why do I not have to use the &
in the function? I can't seem to find an explanation that I can understand on the internet and I was wondering if someone could explain this for me?
Note: these memory addresses are only for illustration.
0x0A | 4
0x0B | 'p' -> 0x0A // Pointer to the value 4 in location 0x0A
0x0C | 'ppint' -> NULL // Initially a null pointer
Performing ppint = &p;
produces the following because here ppint
is the pointer located at 0x0C
.
0x0A | 4
0x0B | 'p' -> 0x0A
0x0C | 'ppint' -> 0x0B
As for the parameter in the changePP
function, I will refer to it as ppintCopy
for less confusion. It's a copy (i.e., a pointer different than ppint
) and modifying it only modifies the copy.
0x0D | 'ppintCopy' -> 0x0C // A pointer that points to `ppint`
Performing ppintCopy = &n
would modify the pointer at 0x0D
which is not the location of the pointer from the main
function. However, deferencing ppintCopy
(i.e., *ppintCopy
) yields 0X0C
which is the pointer from the main
function therefore *ppintCopy = n;
is changing where the pointer 0x0C
points.
Why do I have to use the * to change where ppint points to in the changePP function but not in the main?
With the above illustration I hope it is more clear why it works in main
and why you have to use a different syntax in the changePP
function.
Also why do I not have to use the & in the function?
In the main
function the variable ppint
is of type int**
(i.e., a pointer to a pointer) and p
is of type int*
. You cannot perform ppint = p;
because the they are different types. This may be easier to see if you remove one level of indirection. For example:
int* pMyInt = NULL;
int myInt = 3;
I think it's pretty self explanatory that this cannot work (i.e., they are different types).
pMyInt = myInt;
However you can take the address of myInt
using the &
operator which results in a pointer to int (i.e., int*
) and since this type is the same as the type of pMyInt
the assignment is now possible.
pMyInt = &myInt;
ppint; // the variable name
*ppint; // dereference the first layer of pointer
*(*ppint); // dereference the first layer of pointer which points to another pointer that contains a **value**
Thus *ppint = n;
means point ppint
to another memory location which is the location assigned to n
or it could be rewritten as *ppint = &n;
After that line, you have deleted the n
but you didn't change its value so the value remains unchanged unless something have accessed and modified it.
The reason why you still retain the value of n
after deleting it is considered as undefined behaviour though.
Pointers are already messy to deal with, you didn't have to make it worse. This works as well:
#include <iostream>
using namespace std;
void changePP(int *ppint) {
*ppint = 9;
}
int main() {
int p = 4;
int *ppint = &p;
cout << *ppint << endl; // this could be replaced with /*p*/
changePP(ppint); // note you could have replaced this parameter with /*&p*/
cout << *ppint << endl; // this could be replaced with /*p*/
}
Let me try to explain what your code is doing, but please for future, don't ever do it this way. Do it the way I've shown
#include <iostream>
using namespace std;
void changePP(int **ppint) {
int *n = new int; // you allocate memory for a single integer (again it is uninitialised)
*n = 9; // the value at the above pointer is now changed to 9
*ppint = n; // here you have just dereferenced a pointer to pointer which gives you a pointer, so in essence you are changing the location in memory where this pointer is pointing and it is now pointing to whatever memory address n was
delete n;
}
int main() {
int **ppint = NULL; // Here you have declared a pointer to pointer which is NULL
int *p = new int; // You can do better here with /*new int(4)*/
*p = 4; // this changes the value that p initially held (which could be anything)
ppint = &p; // reference to a pointer always creates a pointer to a pointer and since that is what ppint is, you are safe here
cout << **ppint << endl; // print the value nested within this pointer
changePP(ppint); // now you call the function with a variable of type pointer to pointer. Note you could have passed &p as parameter here and it would have still worked
cout << **ppint << endl;
}
What is the moral of the story?
When passing a parameter v
to a function,
&v
will produce a pointer to v*v
will dereference v and will give you access to whatever v
was pointing toWhen v
is a parameter in a function,
&v
will bring the actual object v
into the scope of the function. This is called pass by reference*v
Is a pointer to v, and this is If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With