C++ difference between ** and *& in parameter passing - c++

I have implemented operations on a list, one of them is add, and since i don't want to return anything, i read that i had to use **, and it works, but i saw on another place that it is passed as *&, but i don't know the difference
addNode( node *&head, int value)
addNode(node **head, int value)
What is the difference, and which one is better, or do they mean the same?
I know the second is pointer to a pointer.
Thanks

The first (**) is a pointer to a pointer and the second (*&) is a reference to a pointer.
A reference and a pointer are conceptually quite similar. But there are some important differences, for example:
A reference cannot be NULL (but it can refer to a pointer which points to NULL).
You can't modify a reference to refer to something else.
You need to dereference a pointer to access the value.
See this related question for more differences:
Difference between pointer variable and reference variable in C++

With:
addNode( node *&head, int value)
...the type of head is "reference to pointer-to-node".
With:
addNode(node **head, int value)
... the type is "pointer-to-pointer-to-node".
A pointer and a reference are not the same thing. A simple way to think of a reference is as a dereferenced pointer.
You would need different syntax to call both versions:
node* my_node = 0;
addNode(my_node, 0); // syntax for first version
addNode(&my_node, 0); // syntax for 2nd version
There are semantic differences as well. When you pass a pointer, you can pass NULL. When you pass a reference, you can't. This being a function that takes a ref-to-ptr confuses the matter a little, so let's change the problem a bit:
void make_string(string& str_ref)
{
str_ref = "my str";
}
void make_string_again(string* str_ptr)
{
*str_ptr = "my other string";
}
These two finctions do the same thing but one takes a string reference while the other takes a string pointer. If you were to do this:
string str;
make_string(str); // OK
make_string_again(&str); // OK - &str is a pointer to a real string
make_string_again(0); // Not OK - compiles but will crash when function dereferences the null pointer
You can see it becomes difficult (but not impossible) to call make_string with a null pointer. This could help you to implement better functions in the case where you expect that make_string will never be called with an invalid object.

This is the difference between pass by value and pass by reference. Pass by reference, basically, implicitly does the reference and dereference that the double pointer gets you.

Related

the purpose of function parameters with two indirection operators (C++)

What is the purpose of a function parameter that has two indirection operators?
Since a call by reference is changing the value of the original variable I thought that a function parameter with two indirection operators might change the address of the original value.
But as my attemp below shows, it does not:
void addrchanger(int**);
int main()
{
int value1 = 4;
int* value1ptr = &value1;
std::cout<<&value1<<std::endl;
addrchanger(&value1ptr);
std::cout<<&value1<<std::endl;
//the address of value1 doesn't change.
}
void addrchanger(int** foo)
{
//this is an attempt to change the address of value1 to the next slot
++**foo;
}
The purpose is to pass a pointer to pointer(s) or a pointer to array(s). Such practise is C-like for historical functions like main() char** argv (that is why you also want an argc, because the size cannot be deduced by the pointer). It is also used when you want to be returned a pointer, so you pass a pointer to a pointer, like in many Win32 functions.
For example in StringFromIID
HRESULT StringFromIID(
REFIID rclsid,
LPOLESTR *lplpsz
);
you would pass a double pointer as the 2nd parameter (a wchar_t**) in order to be returned a pointer, which them must be deallocated like the doc says.
Avoid that completely nowadays in C++ and use std::vector in whatever depth is necessary.
The void addrchanger(int** foo) function can change:
the value: (**foo)++ making int value1 to 5
and address: (*foo)++ making value1ptr point to the next space after value1
I believe you expected the ++**foo to move value1 to the next position, which is not the case.
The pointer to pointer is also useful for matrix declarations, but most libraries such as the GNU scientific library, BLAS, OpenGL glLoadMatrixf(), prefer the use of a single pointer.
When p is of type int **,
++**p
increases the value of the int represented by **p.
In order to change the address of the int pointed to, you would use
++*p
With direct access to your variable, you would use one * less for everything:
int *p;
++*p; // increment the int value
++p; // increment the pointer
But inside such a function, every arguments is just a copy, so if you want to change something outside, you need a pointer to it, which means that one more * is used for everything.
function f(int **p) {
++**p; // increment the int value
++*p; // increment the pointer
// you can also increment the argument
// but you can't know whether it will then
// still point to another int pointer:
++p
}
In addition, you can use & instead of * in C++ which is used only for declaring a variable as a reference and then works like a secret, hidden pointer. You use one less * again, like outside the function at the beginning.
function f(int *&p) {
++*p; // increment the int value
++p; // increment the pointer
// you can also not increment the reference itself,
// as it is a hidden pointer.
}
This sounds dangerous because who would want secret pointers? But it is very common in C++ because people like typing less * all over the place.

What is the "Pass by * &" for?

What does it mean? I understand the use of pass by reference is to pass in the reference so you can directly alter it without the need of a return, and pass by pointer is similar but with a slower runtime. However, I do not understand what * & does. For an example,
foo(int * & var) { }
It passes a pointer by reference so that you can change what the pointer points to and have those changes reflected to the caller.
For example:
void notByReference(int *p) {
p = nullptr;
}
void byReference(int *&p) {
p = nullptr;
}
int main() {
int *i = new int;
notByReference(i); //i is not changed since a copy of the pointer was passed
byReference(i); //i itself is changed, leaking memory
}
This allows you to pass a pointer by reference. Which gives the function the opportunity to modify the pointer and have that modification seen by the caller.
You don't need to stop there. You can pass by reference a pointer to pointer to int, for example.
void foo(int** &var)
Keep in mind that type qualifiers like & and * are independent of each other. When you see some_type& it simply means "reference to sometype", which in turn means that the function sees the caller's version of the argument and can modify it. When sometype is a pointer it just means that the type of the caller's version of the argument is a pointer, and the function can modify that pointer.

On C++ pointers and references, clarification needed

What of the below is wrong please?
It is my understanding that a pointer represents an address of something of some type.
So, int i = 18, a pointer to it is int *pI = &i;
The following 2 declarations are valid
void foo (int &something) // Will accept an address of something
void bar (int *something) // Will accept a pointer to something
When we declare a function as
void bar (int *something)
We better send a pointer to something. Indeed, foo(pI) works.
Following the same logic, when looking at
void foo (int &something)
We should send it an address of something pointing to an int as an argument, so then:
Why is foo(&i) wrong?
void foo (int &something) // Will accept an address of something
This is incorrect: int& is a reference, a concept that is similar to pointers in certain ways, but not at all identical.
References are similar to pointers in that a value can be changed through a reference, just like it can be changed through a pointer. However, there is no such thing as "null reference", while NULL pointers are very common.
When you call a function that takes a reference, you simply pass the variable the reference to which you are taking - no & operator is required:
void foo (something); // "something" must be a variable
The declaration void foo (int &something) takes a reference variable, not a pointer.
You call it exactly the same as you would call void foo (int something), except that something is passed by reference, not by value.
void foo (int &something) // Will accept an address of something
No, though I can understand the confusion. That function takes a reference to int. References are guaranteed to be non-null in a well defined program. It is similar conceptually to a pointer, but semantically different.
To call that function you don't need to do anything special.
int i = 10;
foo(i); // passed to foo by reference
Because in C++ the & means "reference type" in the context of a function prototype as you are using it here. Your function:
void foo (int &something)
is actually specifying that an integer reference type should be passed, so you would simply call this function like this:
foo(i);
Note that in this case you are still passing the address of i into the function, but you are doing it as a reference type rather than a raw pointer.
There are two different meanings for &.
The first is to create a pointer from an existing variable.
The second is to make a reference.
Even though they both use the same character, they are two completely different things.

Difference between & and * as a parameter

What is the difference between the following two parameter types? The first accepts a pointer, which is in effect a memory address, and the second is also a memory address?
foo(float& bar)
{
// do stuff
}
foo(float* bar)
{
// do stuff
}
Could you not call both with:
float pow = 3.0f;
foo(&pow);
or
float* pow = 3.0f;
foo(pow);
A pointer can be NULL, while a reference can't. This can be useful if you need to pass a NULL object for whatever reason.
With the pointer syntax, you pass a pointer when you call the function. With references, you just pass the variable:
refer(float& bar) {}
point(float* bar) {}
float afloat = 1.0f;
refer(afloat);
point(&afloat);
This means with the pointer syntax you have to pass a pointer when you call the function. With the reference syntax, you don't know if the function takes it by reference or by value without looking at the function definition.
With the reference syntax you don't have to dereference the pointer in your function, and work with it more naturally in your // do stuff section.
foo(float& bar)
{
bar = 3.0f;
}
// versus
foo(float* bar)
{
*bar = 3.0f;
}
No, they are not the same. The first is taking a parameter by reference and would be called like this:
float pow = 3.0f;
foo(pow) // foo can change the value of pow!
the second accepts a pointer and could be called by either of your examples (both of which are passing a pointer, not a reference).
NOTE: your second example, while it passes a float* does not properly initialize the pow variale, and therefore won't compile. Instead, something like this would work:
float *pow = new float(3.0);
foo(pow);
delete pow;
While references have similarities to pointers, it is not mandated that they are implemented internally by pointers. For example, often the compiler can inline calls and just modify the argument directly, no pointer passed in that case.
In general, think of a reference as "just another name" for a variable. For example:
Person Samuel_Clemens;
Person &Mark_Twain(Samuel_Clemens); // just another name
The difference is that the first cannot receive a null pointer, while the second can.
But with a bit of effort you can make the first receive null pointer too:
float *a = null;
pow(*a);
Edit: All the following proved to be wrong, I'll keep it as reference for the comments:
The difference is that the reference version will throw an exception when dereferencing a null reference while pointer version will just segfault:
float *a = null;
float &b = *a; // works... somehow?
b = 1; // throws exception
*a = 1; // segmentation fault
float* is a pointer to a float number, whereas float& is a reference to a float number.
With a pointer, you can say function(null) letting the argument point to null (which represents nothing in particular, and often causes undefined behaviour (=crash)). A reference can't reference to nothing (at least not that easy).
When using float*, you will always treat this argument as a pointer, and the compiler does as well. When you use float&, you can treat it as a "normal" (i.e. non-pointer) variable, but it is as if you were using a pointer.
In the first (reference), you are interested on reading and writing the original variable. In the secondth (pointer), you are interested on receiving the address of the original variable.
The difference is mostly taste, except the fact that the pointer version allows you to not-pass any value using a NULL value.

Does dereferencing a pointer make a copy of it?

Does dereferencing a pointer and passing that to a function which takes its argument by reference create a copy of the object?
In this case the value at the pointer is copied (though this is not necessarily the case as the optimiser may optimise it out).
int val = *pPtr;
In this case however no copy will take place:
int& rVal = *pPtr;
The reason no copy takes place is because a reference is not a machine code level construct. It is a higher level construct and thus is something the compiler uses internally rather than generating specific code for it.
The same, obviously, goes for function parameters.
In the simple case, no. There are more complicated cases, though:
void foo(float const& arg);
int * p = new int(7);
foo(*p);
Here, a temporary object is created, because the type of the dereferenced pointer (int) does not match the base type of the function parameter (float). A conversion sequence exists, and the converted temporary can be bound to arg since that's a const reference.
Hopefully it does not : it would if the called function takes its argument by value.
Furthermore, that's the expected behavior of a reference :
void inc(int &i) { ++i; }
int main()
{
int i = 0;
int *j = &i;
inc(*j);
std::cout << i << std::endl;
}
This code is expected to print 1 because inc takes its argument by reference. Had a copy been made upon inc call, the code would print 0.
No. A reference is more or less just like a pointer with different notation and the restriction that there is no null reference. But like a pointer it contains just the address of an object.