I am currently taking a data structures and algorithms class and my professor gave us material that included functions that take in pointer values and pointer/reference values.
These functions would look like this:
int function1(int a); // Pass by value
int function2(int &ref); // Pass by reference
int function3(int* ptr); // This will take in a pointer value
int function4(int*& ptr); // This will take in a pointer/reference value
I understand the difference between pass by value, and pass by reference. I also have tried implementing both of the latter two examples as basic functions, but I am not entirely sure how these two arguments differ from pass by reference or how they differ from each other.
Could somebody explain how these two functions parameters work and how they could be used practically?
[...] but I am not entirely sure how these two arguments differ from
pass by reference or how they differ from each other.
In the first function
int function3(int* ptr);
// ^^^^
you pass the pointer to an int by value. Meaning int* by value.
In second one,
int function4(int*& ptr);
// ^^ --> here
you pass the pointer to the int by reference. Meaning you are passing the reference to the int* type.
But how does passing the pointer by value and by reference differ in
usage from passing a regular variable type such as an integer by value
or reference?
Same. When you pass the pointer by value, the changes that you do the passed pointer(ex: assiging another pointer) will be only valid in the function scop. On the otherside, pointer pass by reference case, you can directly make changes to the pointer in the main(). For example, see the folloiwng demonstration.
#include <iostream>
// some integer
int valueGlobal{ 200 };
void ptrByValue(int* ptrInt)
{
std::cout << "ptrByValue()\n";
ptrInt = &valueGlobal;
std::cout << "Inside function pointee: " << *ptrInt << "\n";
}
void ptrByRef(int *& ptrInt)
{
std::cout << "ptrByRef()\n";
ptrInt = &valueGlobal;
std::cout << "Inside function pointee: " << *ptrInt << "\n";
}
int main()
{
{
std::cout << "Pointer pass by value\n";
int value{ 1 };
int* ptrInt{ &value };
std::cout << "In main() pointee before function call: " << *ptrInt << "\n";
ptrByValue(ptrInt);
std::cout << "In main() pointee after function call: " << *ptrInt << "\n\n";
}
{
std::cout << "Pointer pass by reference\n";
int value{ 1 };
int* ptrInt{ &value };
std::cout << "In main() pointee before function call: " << *ptrInt << "\n";
ptrByRef(ptrInt);
std::cout << "In main() pointee after function call: " << *ptrInt << "\n\n";
}
}
Output:
Pointer pass by value
In main() pointee before function call: 1
ptrByValue()
Inside function pointee: 200
In main() pointee after function call: 1
Pointer pass by reference
In main() pointee before function call: 1
ptrByRef()
Inside function pointee: 200
In main() pointee after function call: 200
Passing a pointer by reference allow you to change the pointer and not only the pointed value. So if you do and assignment of pointer in the function int function4(int*& ptr) in this way :
ptr = nullptr;
the caller have the pointer set to "nullptr".
In the function int function3(int* ptr) the pointer passed is copied in the variabile ptr that is valid only in the scope of function3. In this case you can only change the value pointed by the pointer and not the pointer ( or to better specify you can change the pointer but only in the scope of the function ). So the previous expression ptr = nullptr; has no effect in the caller.
If you want to modify an outside int value, use this:
int function1(int* ptr) {
*ptr = 100; // Now the outside value is 100
ptr = nullptr; // Useless. This does not affect the outside pointer
}
If you want to modify an outside int* pointer, i.e. redirect that pointer, use this:
int function2(int*& ptr) {
ptr = nullptr; // Now the outside pointer is nullptr
}
Or this:
int function3(int** ptr) {
*ptr = nullptr; // Same
}
The first and second are pass by value and reference respectively as commented in the code.
The third one takes an integer pointer as a parameter by value, which can be assigned a memory location but the value of the pointer only changes locally inside the function scope.
The fourth one holds the value of an integer variable with reference as there is an amperson(&) for referencing the value(which is a pointer).
They are function declarations, not definitions so unless they are defined with a function body you can't explore its practical uses. (or a list of endless possibilities from what you could do with an integer value)
If you want a case of pass by value vs pass by reference, the classic example would be the swapping of two or more values within a function (without returning values), wherein pass by reference works and pass by value fails or your first and third functions would change the values locally inside the function only whereas the second and fourth ones would change the value in its entirety.
Related
First code:
int a = 1;
void func(int* ptr) {
ptr = &a;
}
int main() {
int nvar = 2;
int* pvar = &nvar;
func(pvar);
std::cout << *pvar;
}
//Output: 2
Second code:
int a = 1;
void func(int*& ptr) {
ptr = &a;
}
int main() {
int nvar = 2;
int* pvar = &nvar;
func(pvar);
std::cout << *pvar;
}
//Output: 1
The only difference is the '&' character in the 'func' function. But can someone explain me, what it does in this situation?
I know what it does, but in the second code it is combined with * , and I dont know what this combination means
T& denotes "reference to T".
Now replace T with whatever you like. Eg for pointer to int, T==int* we have int*& which is a reference to a pointer to int.
It is no different to passing non-pointers to functions as references. When ptr is passed by value then func works on a copy, when passed by reference func works on the instance passed in.
The & signifies passing by reference:
The difference between pass-by-reference and pass-by-value is that modifications made to arguments passed in by reference in the called function have effect in the calling function, whereas modifications made to arguments passed in by value in the called function can not affect the calling function. Use pass-by-reference if you want to modify the argument value in the calling function. Otherwise, use pass-by-value to pass arguments.
I think that says it better than I could.
Is there a difference or preferred way of altering a pointer in a function? Take this snippet for example
void change(int** ptr) {
**ptr = 50;
*ptr = nullptr;
}
void change(int*& ptr) {
*ptr = 50;
ptr = nullptr;
}
int main()
{
int a = 5;
int* ptr = &a;
int** ptr2 = &ptr;
std::cout << "value: " << a << std::endl;
std::cout << "value: " << ptr << std::endl;
std::cout << "value: " << ptr2 << std::endl;
change(ptr2);
//change(ptr);
std::cout << "value: " << a << std::endl;
std::cout << "value: " << ptr << std::endl;
std::cout << "value: " << ptr2 << std::endl;
system("pause");
}
It seems like both of the change functions can achieve what I'm asking, but I'm not sure on the difference, other than the reference function doesn't create a copy of the pointer?
You can have a null pointer, but not a null reference.
You can supply the first with nullptr, and it will compile1, because there is an implicit conversion from std::nullptr_t to int**. If you tried to supply the second with nullptr, it will fail. The best match would be the conversion std::nullptr_t to int*, but you can't bind a mutable reference to a temporary.
I go over various situations for different ways of parameter passing in this answer, which also includes object ownership considerations (with std::unique_ptr)
1. The behaviour will be undefined, because you dereference it.
Is there a difference ... between ptr** and ptr*& ...
Yes. The former is a pointer, to an object of type ptr*, while the latter is a reference to an object of type ptr*.
or preferred ...
void change(int** ptr) {
**ptr = 50;
*ptr = nullptr;
}
void change(int*& ptr) {
*ptr = 50;
ptr = nullptr;
}
Advantages of a reference
You'll find that the reference is implicitly indirected, which makes the syntax simpler and that usually helps readability. This is particularly important in case of reference / pointer to a pointer. Same advantage applies to getting a reference: You don't need to use the address-of operator.
Another advantage is that a reference cannot be reassigned to refer to another object. This makes it simpler to read programs that use references, since you don't need to figure out whether a reference is reassigned within a long algorithm; You know that it isn't.
Another advantage is that a reference cannot be null. Therefore you don't need to check for such eventuality within the function. If you pass null to the first example function, the behaviour would be undefined, which is a very bad thing.
Disadvantages of a reference
You'll find that the reference is implicitly indirected. This can be confusing to people who are familiar with only value types (C programmers).
Another disadvantage is that a reference cannot be reassigned to refer to another object. This appears to not be a problem for your function since you don't need to refer to more than one object, but in general, there are situations where it would be useful.
Another disadvantage is that a reference cannot be null. This appears to not be a problem for your function which is presumably never intended to handle such case. But in general, there are situations where you want to represent a referential relation to non-existing object.
Preferences are personal, but in my opinion, the advantages of the reference outweigh the disadvantages, except when you need one of the features that are not possible (nullability, re-assignment)
It's largely a matter of personal taste.
That said, when calling void change(int** ptr), because you'd tend to pass the address of something using &, it is clearer at the calling site that the "something" could be modified by the function. If you use the int*& ptr overload, it's not as clear as the calling syntax is identical for pass-by-value and pass-by-reference.
Aside from the above, I tend to use pointers as function parameters if nullptr is allowed, and references if not.
I am kind confused about this case:
Declare a pointer:
int b =10;
int*a=&b;
Here & takes the address of b.
Consider another example:
/* Reference to the calling object can be returned */
Test& Test::func ()
{
// Some processing
return *this;
}
this should be a pointer, *this is the obeject pointed.
But here we are asking to assign *this to &Test.
What should we modify the code to let the function return the address. Should we still use Test& ?
In C++ there're two different syntax units:
&variable; // extracts address of variable
and
Type& ref = variable; // creates reference called ref to variable
Easy usage example:
int v = 5;
cout << v << endl; // prints 5
cout << &v << endl; // prints address of v
int* p;
p = &v; // stores address of v into p (p is a pointer to int)
int& r = v;
cout << r << endl; // prints 5
r = 6;
cout << r << endl; // prints 6
cout << v << endl; // prints 6 too because r is a reference to v
As for using references in functions, you should google "passing by reference in C++", there're many tutorials about it.
Firstly, this is a pointer. The * dereferences the pointer, meaning return *this; returns the object, not a pointer to it.
Secondly, Test& is returning a reference to a Test instance. In your case, it is a reference to the object. To make it return a pointer, it should be Test*.
It makes more sense if you read a pointer declaration from right to left.
Test* func(); //When I call func, and dereference the returned value, it will be a Test
But here we are asking to assign *this to &Test.
No... you're asking for the value/expression *this to be used to return a Test&, which is a reference to a Test object. What that does is return a reference to the object on which func() is invoked.
What should we modify the code to let the function return the address. Should we still use Test& ?
You should use Test* instead... pointers are addresses, and having changed the return type you could return this (which is a pointer), but not *this because *this is not a pointer.
If I have a function that takes a reference to a map:
pair<int,int> myFunc(map<int,char> &myVar){...}
I can pass it a map without needing the '&'.
myFunc(someMapitoa);
Is there any difference? Is a copy made and then thrown away? Should I use the '&' anyway?
C++ is pass-by-value by default.
So, this makes a copy:
void foo (bar b);
This does not:
void foo (bar & b);
This makes a copy of a pointer, but not the actual data that it points to:
void foo (bar * b);
If you really want to get deeper into it then see this SO post about move semantics.
Anyway, for the above three examples they are all called the same way:
#include <iostream>
using namespace std;
int alpha (int arg) {
// we can do anything with arg and it won't impact my caller
// because arg is just a copy of what my caller passed me
arg = arg + 1;
return arg;
}
int bravo (int & arg) {
// if I do anything to arg it'll change the value that my caller passed in
arg = arg + 1;
return arg;
}
int charlie (int * arg) {
// when we deal with it like this it's pretty much the same thing
// as a reference even though it's not exactly the same thing
*arg = *arg + 1;
return *arg;
}
int main () {
int a = 0;
// 1
cout << alpha (a) << endl;
// 1
cout << bravo (a) << endl;
// 2
cout << charlie (&a) << endl;
return 0;
}
You should think of this in terms of what is being initialized from what.
When you call a function, each argument is used to initialize the corresponding parameter. If the parameter is declared with reference type, it's a reference. If the parameter is not declared with reference type, it's an object.
The initialization of a reference to class type T from an expression of type T never makes a copy.
The initialization of an object of class type T from an expression of type T either copies or moves.
The rules here are the same as the rules for initializing non-parameter variables, as in:
T t = ...
T& r = ...
The fact that a function may take a reference to an argument even when there is no explicit notation at the call site is viewed by some as confusing. This is why some style guides ban non-const reference parameters (such as the Google C++ style guide) and force you to declare the argument as a pointer so that & must be used at the call site. I don't advocate this coding style, but it is an option you might want to consider.
I am a C guy and I'm trying to understand some C++ code. I have the following function declaration:
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
How does the function signature differ from the equivalent C:
int foo(const char *myname)
Is there a difference between using string *myname vs string &myname? What is the difference between & in C++ and * in C to indicate pointers?
Similarly:
const string &GetMethodName() { ... }
What is the & doing here? Is there some website that explains how & is used differently in C vs C++?
The "&" denotes a reference instead of a pointer to an object (In your case a constant reference).
The advantage of having a function such as
foo(string const& myname)
over
foo(string const* myname)
is that in the former case you are guaranteed that myname is non-null, since C++ does not allow NULL references. Since you are passing by reference, the object is not copied, just like if you were passing a pointer.
Your second example:
const string &GetMethodName() { ... }
Would allow you to return a constant reference to, for example, a member variable. This is useful if you do not wish a copy to be returned, and again be guaranteed that the value returned is non-null. As an example, the following allows you direct, read-only access:
class A
{
public:
int bar() const {return someValue;}
//Big, expensive to copy class
}
class B
{
public:
A const& getA() { return mA;}
private:
A mA;
}
void someFunction()
{
B b = B();
//Access A, ability to call const functions on A
//No need to check for null, since reference is guaranteed to be valid.
int value = b.getA().bar();
}
You have to of course be careful to not return invalid references.
Compilers will happily compile the following (depending on your warning level and how you treat warnings)
int const& foo()
{
int a;
//This is very bad, returning reference to something on the stack. This will
//crash at runtime.
return a;
}
Basically, it is your responsibility to ensure that whatever you are returning a reference to is actually valid.
Here, & is not used as an operator. As part of function or variable declarations, & denotes a reference. The C++ FAQ Lite has a pretty nifty chapter on references.
string * and string& differ in a couple of ways. First of all, the pointer points to the address location of the data. The reference points to the data. If you had the following function:
int foo(string *param1);
You would have to check in the function declaration to make sure that param1 pointed to a valid location. Comparatively:
int foo(string ¶m1);
Here, it is the caller's responsibility to make sure the pointed to data is valid. You can't pass a "NULL" value, for example, int he second function above.
With regards to your second question, about the method return values being a reference, consider the following three functions:
string &foo();
string *foo();
string foo();
In the first case, you would be returning a reference to the data. If your function declaration looked like this:
string &foo()
{
string localString = "Hello!";
return localString;
}
You would probably get some compiler errors, since you are returning a reference to a string that was initialized in the stack for that function. On the function return, that data location is no longer valid. Typically, you would want to return a reference to a class member or something like that.
The second function above returns a pointer in actual memory, so it would stay the same. You would have to check for NULL-pointers, though.
Finally, in the third case, the data returned would be copied into the return value for the caller. So if your function was like this:
string foo()
{
string localString = "Hello!";
return localString;
}
You'd be okay, since the string "Hello" would be copied into the return value for that function, accessible in the caller's memory space.
Your function declares a constant reference to a string:
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
A reference has some special properties, which make it a safer alternative to pointers in many ways:
it can never be NULL
it must always be initialised
it cannot be changed to refer to a different variable once set
it can be used in exactly the same way as the variable to which it refers (which means you do not need to deference it like a pointer)
How does the function signature differ from the equivalent C:
int foo(const char *myname)
There are several differences, since the first refers directly to an object, while const char* must be dereferenced to point to the data.
Is there a difference between using string *myname vs string &myname?
The main difference when dealing with parameters is that you do not need to dereference &myname. A simpler example is:
int add_ptr(int *x, int* y)
{
return *x + *y;
}
int add_ref(int &x, int &y)
{
return x + y;
}
which do exactly the same thing. The only difference in this case is that you do not need to dereference x and y as they refer directly to the variables passed in.
const string &GetMethodName() { ... }
What is the & doing here? Is there some website that explains how & is used differently in C vs C++?
This returns a constant reference to a string. So the caller gets to access the returned variable directly, but only in a read-only sense. This is sometimes used to return string data members without allocating extra memory.
There are some subtleties with references - have a look at the C++ FAQ on References for some more details.
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(&number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
*p=*p+100;
return(*p);
}
This is invalid code on several counts. Running it through g++ gives:
crap.cpp: In function ‘int main()’:
crap.cpp:11: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int*’
crap.cpp:3: error: in passing argument 1 of ‘int add(int&)’
crap.cpp: In function ‘int add(int&)’:
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:20: error: invalid type argument of ‘unary *’
A valid version of the code reads:
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
p=p+100;
return p;
}
What is happening here is that you are passing a variable "as is" to your function. This is roughly equivalent to:
int add(int *p)
{
*p=*p+100;
return *p;
}
However, passing a reference to a function ensures that you cannot do things like pointer arithmetic with the reference. For example:
int add(int &p)
{
*p=*p+100;
return p;
}
is invalid.
If you must use a pointer to a reference, that has to be done explicitly:
int add(int &p)
{
int* i = &p;
i=i+100L;
return *i;
}
Which on a test run gives (as expected) junk output:
The value of the variable number before calling the function : 5
The value of the variable number after the function is returned : 5
The value of result : 1399090792
One way to look at the & (reference) operator in c++ is that is merely a syntactic sugar to a pointer. For example, the following are roughly equivalent:
void foo(int &x)
{
x = x + 1;
}
void foo(int *x)
{
*x = *x + 1;
}
The more useful is when you're dealing with a class, so that your methods turn from x->bar() to x.bar().
The reason I said roughly is that using references imposes additional compile-time restrictions on what you can do with the reference, in order to protect you from some of the problems caused when dealing with pointers. For instance, you can't accidentally change the pointer, or use the pointer in any way other than to reference the singular object you've been passed.
In this context & is causing the function to take stringname by reference.
The difference between references and pointers is:
When you take a reference to a variable, that reference is the variable you referenced. You don't need to dereference it or anything, working with the reference is sematically equal to working with the referenced variable itself.
NULL is not a valid value to a reference and will result in a compiler error. So generally, if you want to use an output parameter (or a pointer/reference in general) in a C++ function, and passing a null value to that parameter should be allowed, then use a pointer (or smart pointer, preferably). If passing a null value makes no sense for that function, use a reference.
You cannot 're-seat' a reference. While the value of a pointer can be changed to point at something else, a reference has no similar functionality. Once you take a variable by reference, you are effectively dealing with that variable directly. Just like you can't change the value of a by writing b = 4;. A reference's value is the value of whatever it referenced.