I have a struct, say:
struct Astruct {
int a;
int b;
}
And I have av instance of that struct say:
private:
Astruct My_List;
Then I have a function that I want to get the address of My_List.
public:
void Get_My_List(Astruct* List) {
List = &My_List;
}
However it seems to always set the argument Astruct* List = 0;
I know I probably could make a function called Astruct& Get_Address() or something but in this particular case I would like to know why I can't assign addresses in the argument. I mean it is possible to pass arguments as references and change the data. Or maybe I start to understand the problem now when I write this... Anyway just to be sure, is it possible to change the address the pointer points to via an argument? Or can I just change the data the pointer points to?
I figured it out. Yes it was about confusion, but not pointer confusion, more like argument confusion!
So the problem is that I thought I could "return" values via arguments. I thought that because I have previously created functions that takes a pointer and then the function changes the data the address points to. And yes it is "set" to zero. I mean #john is right, the code can't set it, but it is never changed. Because the value I pass in is initialized to zero and I can't change an argument, in this case Astruct* List. So the pointer I pass remains unchanged.
So what I had to do was to make the function take a pointer to a pointer.
void Get_My_List(Astruct** List) {
*List = &My_List;
}
And pass the address to the pointer instead. In that case I can change the data the pointer points to, which is a pointer.
Thanks, bye!
You can pass the reference-to-pointer:
void Get_My_List(Astruct*& List) {
List = &My_List;
}
and call it like that:
AstructHolder obj{};
Astruct* my_ptr{nullptr};
obj.Get_My_List(my_ptr);
Related
In my project, there is a definition of a function call like this.
int32 Map(void * &pMemoryPointer)
In the calling place, the paramenter passed is void*, why cant we just receive it as a pointer itself, instead of this?
Without knowing what the Map function does, I'd guess that it sets the pointer. Therefore it has to be passed by reference.
Using a reference to a pointer, you can allocate memory and assign it to the pointer inside the function. For example
void DoSomething(int*& pointerReference)
{
// Do some stuff...
pointerReference = new int[someSize];
// Do some other stuff...
}
The other way to make functions like that is to return the pointer, but as the Map function in the question returns something else that can't be used.
Reading it backwards, this means that pMemoryPointer is a reference (&) to a pointer (*) to void. This means that whatever pointer you pass gets referenced, and any modification that the function will do to pMemoryPointer will also affect the original (passed) pointer (e.g. changing the value of pMemoryPointer will also change the value of the original pointer).
why cant we just receive it as a pointer itself, instead of this?
That's because by doing that, you are copying the pointer and any change that you'll make to the copy doesn't reflect to the original one.
void im_supposed_to_modify_a_pointer(void* ptr) { // Oh no!
ptr = 0xBADF00D;
}
int* my_ptr = 0xD0GF00D;
im_supposed_to_modify_a_pointer(my_ptr);
ASSERT(my_ptr == 0xBADF00D) // FAIL!
That's a weird function prototype IMHO, but it means
(Update) that the Map function accepts a reference to a void pointer as a parameter.
So I think, it is equivalent to declaring the function like this:
int32 Map(void** pMemoryPointer)
I have been working on linked lists and trees recently. But i am not sure when to declare a function as:
preorder(struct node* root);
or
preorder(struct node** root);
when both work quite the same. To be more precise when do i have to design my function as double pointer and as a single pointer.
Thanks.
P.S: insertion of a node in linked list needs to have double pointer as in:
insert(struct node** root,int value);
unless the root node is defined as a global value. While the preorder works well with a single pointer. If anyone can explain with this as an example it would be highly helpful.
That depends on what preorder() does. If it prints some stuff without modifying the list/tree, you only need a single pointer. If there is a chance that the root will have to be replaced, you need a double pointer.
This is because arguments are passed by value in C. You cannot modify the original variable if a copy of it is passed to your function:
int inc(int x)
{
x = x + 1; // this will never work
}
To get around this, instead of passing in the argument you can pass in the address of that argument (a pointer to it). The function can then dereference the pointer and modify the value it points to.
// usage: inc(&x) where x is an int
int inc(int *ptr)
{
*ptr = *ptr + 1; // this will work
}
With your list/tree, you are already using pointers. This lets you access and modify the pointed-to object (e.g. get/set the next member of the root), but doesn't let you modify the pointer itself (e.g. replace the root with a different node). To do that, another level needs to be introduced, hence the pointer-to-pointer-to-node.
preorder(struct node** root);
Here you pass the address of root, because you may wish to update it withing the function.
preorder(struct node* root);
Here you simply use root to transverse the data structure, without modifying the root.
It's kind of confusing, but I will give it a shot and maybe my way of explaining will make sense to someone :)
Every variable in a function's scope is defined in a standard way, essentially.. (variable type) (variable name). Whether that's:
int foo; // an int called foo
or
char *bar; // a char * called bar
or
struct xyz *blah; // a struct xyz * called blah
and the way you treat foo, bar, and blah are the same when you pass them as arguments to another function. If you want the called function to just look at or use the variables, you can pass them as they are (by value) which creates a copy of the values (an int, or the address of a char, or the address of a struct xyz). So, if you change the value of the int, or the address of the struct xyz in the called function, it is only changed for that local copy of the original variable.
If you want the called function to actually change the value of the original variable (increment foo, malloc memory for bar, or change which element in a list blah points to for example) you need to tell the called function WHERE to make that change (pass them by reference) which results in the called function being declared as f(int *foo) or f(char **bar) or f(struct xyz **blah).
People get caught up on levels of indirection but all that really matters when you're calling another function is what your intentions are with respect to using or changing the variables in the local scope.
You pass a pointer instead when you want to change the thing being passed to the routine. Your confusion arises because the thing is also a pointer.
So if you want to pass a pointer to a routine, and you also want to (potentially) modify the pointer itself, use a double pointer.
If you want to pass a pointer to a routine but all you want to do is change or query what the pointer is pointing to use a single pointer.
That's the difference, do you want to change the pointer or do you want to access what the pointer is pointing to.
Since question is tagged both C and C++, here is a look at the difference from that perspective. This answer does not touch C++ container classes or smart pointers, which should usually be preferred in C++ code. Below are 4 cases, two which can modify caller's struct and caller's pointer, and two which can only modify contents of given struct.
C++ modify pointer
When you want the function to modify a pointer, and have the pointer values returned to the caller in C++, you would do this using a reference to pointer:
void clearNode(struct node *&n){
n->field = 0; // modify caller's struct
n = nullptr; // set caller's pointer to NULL (C++11)
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // OK, np becomes null, n.field becomes 0
clearNode(&np); // will not compile, &np is not right type
clearNode(&n); // will not compile, &n is not lvalue
C modify pointer
In C, same code would be like this (also works in C++, though above version would be better and cleaner):
void clearNode(struct node **n){
(*n)->field = 0; // modify caller's struct
*n = NULL; // set caller's pointer to NULL
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // will not compile, np is not right type
clearNode(&np); // OK, np becomes NULL, n.field becomes 0
clearNode(&n); // will not compile, &n is not of right type
C modify only struct
But if we write same code with just pointer, it will work just a bit differently:
void clearNode(struct node *n){
n->field = 0; // modify caller's struct
n = NULL; // change local parameter, which in this case has no effect anywhere
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // OK, except np is not modified, n.field becomes NULL
clearNode(&np); // will not compile, &np is not of right type
clearNode(&n); // OK, n.field becomes NULL
C++ modify only struct
And finally, same code in C++ would be cleaner this way:
void clearNode(struct node &n){
n.field = 0; // modify caller's struct
// no pointer, nothing to set to NULL
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // will not compile, np is not of right type
clearNode(&np); // will not compile, &np is not of right type
clearNode(&n); // will not compile, &n is not of right type
// these work, n.field becomes 0:
clearnode(n);
clearnode(*np);
Your question
So, the thing to take from above is, if you need to modify callers pointer, pass pointer to pointer (C and C++) or refrence to pointer (C++). This comes at a cost: you must always pass a modifiable pointer variable, and double indirection also has small overhead. Syntax for both is shown above.
If you do not need to modify callers pointer, but need to modify the struct contents, pass a pointer (C and C++) or reference (C++) to struct. Syntax for both is shown above.
Third case, when you don't need to modify anything, is not covered above, but has 3 basic alternatives: pass by value (C and C++, clean syntax but copies entire struct), pass by pointer to const (C and C++, a bit uglier syntax but passes just address) or pass by const reference (C++ only, clean syntax and passes only address).
To summarize, use double pointer (or reference to pointer) when you need to modify caller's pointer. Otherwise, pass a pointer (or a reference), or even a value if struct is small.
In the first function call, I'm sending in a matrix pass by reference. Isn't the second way the same? I thought matrices were default pass by reference.
Here's the first case:
phi= new double[15]; //phi is a dynamically allocated array
function(double *phi) //calls phi with what SHOULD be default pass by reference
Second case:
function(double *&phi) //calls phi with pass by reference?
There should be no difference between the two, right?
The reason I ask is because my code segment faults when I neglect the '&' sign and try to assign a value to phi outside of the function that I dynamically allocated it in.
In the first case, your function declaration accepts a pointer by value.
In the second case, your function declaration accepts a pointer by reference. You could change the pointer in the function.
You seem to be misunderstanding what "passing as reference" means. When you pass a variable as a reference, you give the function the ability to change the value of the variable.
Say I have a function defined as:
doIt(int i)
and I call it like this:
main()
{
int a = 2;
doIt(a);
}
The function can't change the value of the "a" variable.
In your case, you are using a pointer. If I had the following function:
doItWithAPointer(int* a)
and called it like this:
main()
{
int a = 2;
int* pa = &a;
doItWithAPointer(pa);
}
I could now change the value of "a". Why? because I can access its value through the pointer. What I can't do is change the value of the actual parameter, in this case "pa" or, in other words, make it point to another address.
Now, finally if I declare my function like this:
doItWithAPointerReference(int* &a)
and called it like this:
main()
{
int a = 2;
int* pa = &a;
doItWithAPointerReference(pa);
}
I can still change the value of the "a" variable through the pointer, but I can also directly change the value of "pa" since I have a reference to it!
Imagine a function like this:
function(Human *&human){
// Implementation
}
Can you explain what exactly a *& is? And what would it be used for? How is different than just passing a pointer or a reference? Can you give a small and explanatory sample?
Thank you.
It is like a double pointer. You're passing the pointer by reference allowing the 'function' function to modify the value of the pointer.
For example 'human' could be pointing to Jeff and function could modify it to point to Ann.
Human ann("Ann");
void function(Human *& human)
{
human = &ann;
}
int main()
{
Human jeff("Jeff");
Human* p = &jeff;
function(p); // p now points to ann
return 0;
}
void doSomething(int &*hi);
will not work. You cannot point to references. However, this:
void doSomething(int *&hi); // is valid.
It is a reference to a pointer. This is useful because you can now get this pointer passed into the function to point to other "Human" types.
If you look at this code, it points "hi" to "someVar". But, for the original pointer passed to this function, nothing will have changed, since the pointer itself is being passed by value.
void doSomething(int *hi)
{
hi = &someVar;
}
So you do this,
void doSomething(int *&hi)
{
hi = &someVar;
}
So that the original pointer passed into the function is changed too.
If you understand "pointers to pointers", then just imagine that, except when something is a reference it can be treated like a "non-pointer".
"Takes an address of a pointer" - No, it doesn't. It takes supposed to take a reference to a pointer.
However, this is a syntax error. What you probably meant is
rettype function(Human *&human)
(Yes, it's also missing a return type...)
Since you wrote this code off the top of your head, I'm going to assume you meant to do something like this:
void f(T *&) {}
This function signature allows the pointer passed to become modifiable, something that isn't allowed with the alternate syntax int *. The pointer is effectively passed by reference as others here call it.
With this syntax, you are now able to modify the actual pointer and not just that which it points to. For example:
void f(int *& ptr) {
ptr = new int;
}
int main() {
int * x;
f(ptr); // we are changing the pointer here
delete x;
}
Summary (assume types are in parameters):
T *: We are only able to change the value of the object to which the pointer points. Changing the parameter will not change the pointer passed.
T *&: We can now change the actual pointer T, and the value of the object to which it points *T.
Even though it looks just like the address-of operator, it's not - it's a reference parameter. You use a reference when you want to be able to change the value at the caller's end. In this case the pointer is probably being set or changed within the function.
Lets say I have a class "A" and this function:
void initializationFunction(A* classPointer)
{
...
...
classPointer = new A(.....);
}
I write:
A* classPointer;
Then I pass this pointer to this function:
initializationFunction(classPointer);
This will not work unless I pass it by reference in the function declaration:
void initializationFunction(A*& classPointer);
I thought reference passing was for non-pointer type variables. I mean you don't need to pass an array by reference...
Thanks for the explanations :)
Yeah, that is true. You've to pass the argument by reference (or you can pass A** instead).
But the best solution is to write the constructor of A in such way that you wouldn't need this function in the first place. That is, whatever you're doing in this function, you should be doing that in the constructor itself.
If, however, you cannot edit the class, then you can do this instead:
A *initializationFunction()
{
A *obj = new A(.....);
//...
return obj;
}
A *classPointer = initializationFunction();
In my opinion, this approach is better than yours.
Note I didn't change the name of the function and other variables. I guess that isn't the point of the post. But I believe you would want better names for real code.
Either you declaration with the reference or the following one will do:
void initializationFunction(A** classPointer);
The point is that you are passing in a pointer argument and that you want to modify the value it had in the caller. This is an out parameter and out parameters should be passed by reference, not by value (reference here means either through a pointer or reference). This out parameter is a pointer, so you should pass a pointer to that pointer or a reference to that pointer.
In other words, you need to access the original argument in the caller stack to be able modify it. In the declaration
void initializationFunction(A* classPointer);
classPointer is akin to a local variable defined inside of initializationFunction and is just a copy of the classPointer you allocated in the caller function. Modifying a copy of classPointer will not modify the original variable, so you need a pointer to the original variable to be able to modify it. The same holds true if you use a reference to the original classPointer.
An alternative approach you have is returning the new classPointer from your function:
A* initializationFunction(void);
in this case the caller would simply do:
A* classPointer = initializationFunction();
You can pass any variable by reference. The difference between passing by reference and passing by value, is that when you pass by reference, you are in fact passing the very same pointer that is pointing to the value in that memory location, and when you pass by value you are just passing another reference to that memory location, and therefore anything you assign to it will NOT change the value of the parameter passed.
Either use a double pointer (a**) or a reference as you did.
In your first example, the pointer is passed by value (ie. the function gets a copy of the pointer). The object that the pointer points to is of course the same both in the calling code and inside the function.
In the second example, the pointer is passed by reference (ie. the function basically uses the same pointer as the calling code).
say you had a windows shortcut pointing to a text file in "My Documents".
you can copy that shortcut and paste it anywhere in windows, double click on it, and it opens the text file in "My Documents". That is passing by reference / pointer. The shortcut points to "where", then you use it to change the "stuff".
However, the code you posted doesn't "open" the file pointed to by the shortcut. It actually changes the shortcut to point to (actually create ) a new "file". But since the shortcut itself was first copied ( passed by value ), the effect is that you allocated memory but cannot access it. So analogously you changed the shortcut, created a "file", but then deleted the directory with that shortcut in there ( but your file is then lost in outer space !).
Unfortunately, there is really no analogy for passing a shortcut itself by reference, you would basically have to copy the shortcut back out of the directory, then replace the original text file in "my documents" with a shortcut to this new "file". Hope this helps instead of confuses it further :(.
The reason you have to pass the pointer by reference is that you're actually changing where in memory it points to. If you had already assigned it to an object and wanted to modify that object, passing it directly to the function would be fine.
When you do a Aptr = new A(...), you are
- Creating an 'A' object somewhere on the heap
- Assigning the address of the newly created object to Aptr
If the function doesn't have a reference to Aptr, the function can't change its value.
You can pass pointers by reference because pointers are also variables with their own address.
For example, in a 32-bit architecture, you can declare an unsigned int and use it as a pointer.
This is normal.
I explain:
void foo(X* toto)
{
toto=new X();
}
toto value will be poped out from call stack with it's initial value (as any other argument , pointer or not)
since it's not possible to change function argument value UNLESS it's a reference.
so:
void foo(X*& toto)
{
toto=new X();
}
Here you explicitely say toto argument as being X*& (X* for type , and & (reference) to let it's value be modified inside function foo)
Pointer types are the same than any other types. replace X* by int and you'll immediately find that toto won't be changed outside of function call unless passed as reference.
An X** would also have done the trick , using such implementation:
void foo(X** toto)
{
*toto=new X();
}
It should be:
void initializationFunction(A** classPointer)
{
...
...
*classPointer = new A(.....);
}
Call:
initializationFunction(&ptr);
the function will set the argument passed in to the new A(......);
example: http://ideone.com/u7z6W