Phineas
Phineas

Reputation: 319

*& vs & in passing variable to function

I'm trying to understand reference and pointer in C++, and I stumble upon this

#include<iostream> 
using namespace std; 

void swap(char * &str1, char * &str2) 
{ 
char *temp = str1; 
str1 = str2; 
str2 = temp; 
} 

int main() 
{ 
const char *str1 = "GEEKS"; 
const char *str2 = "FOR GEEKS"; 
swap(str1, str2); 
cout<<"str1 is "<<str1<<endl; 
cout<<"str2 is "<<str2<<endl; 
return 0; 
} 

What is *& in the function Swap, and compare to & (Pass by reference) I have learned, is there any different in performance, or how do they work, what should I use?

void swap(char &str1, char &str2) 
{ 
char temp = str1; 
str1 = str2; 
str2 = temp; 
} 

Upvotes: 3

Views: 6576

Answers (4)

Kalloax
Kalloax

Reputation: 21

If you pass a reference to integer to a swap function, you will be copying one variable’s data to other just like this:

void swap(int &a, int &b) 
{ 
    int temp = a; 
    a = b; 
    b = temp;
} 

int main() 
{ 
    int a = 1; 
    int b = 5; 
    std::cout<<"a's adress before swap: "<< &a <<'\n'; 
    std::cout<<"b's adress before swap: "<< &b <<'\n'; 
    swap(a, b); 
    std::cout<<"a's adress after swap: "<< &a <<'\n'; 
    std::cout<<"b's adress after swap: "<< &b <<'\n'; 
    return 0; 
} 

The output is:

a's adress before swap: 0x7ffeeccaba68
b's adress before swap: 0x7ffeeccaba64
a's adress after swap: 0x7ffeeccaba68
b's adress after swap: 0x7ffeeccaba64

So it copied a’s data to temp, then copied b’s data to a, finally copied temp’s data to b. It is okay if you’re passing small objects like integers, however it may cost a significant time and space if you pass big objects like Class objects to swap function.

On the other hand, if you pass a reference to pointer to a swap function, you will be just chancing where pointers are pointing. For example:

#include <iostream>
void swap(int *&a, int *&b){
    int *temp = a;
    a = b;
    b = temp;
}

int main(){
    int x = 1;
    int y = 5;
    int *a = &x;
    int *b = &y;
    std::cout << "where a points before swap: " << a << '\n';
    std::cout << "where b points before swap: "<< b << '\n';
    swap(a, b);
    std::cout << "where a points after swap: " << a << '\n';
    std::cout << "where b points after swap: "<< b << '\n';
    return 0;
}

Notice that in the output, where a and b points chancing after swap:

where a points before swap: 0x7ffee1738a68
where b points before swap: 0x7ffee1738a64
where a points after swap: 0x7ffee1738a64
where b points after swap: 0x7ffee1738a68

In the swap function, firstly temp points where a(pointing x) points, then a points where b(pointing y) points, finally b points where temp points( pointing x). Thus, it just swapped where pointers are pointing and didn’t copy any significant data. So if you need to swap big data objects reference to a pointer is better for time and space.

Upvotes: 2

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

Any type can be referenced in a declaration.

For example

#include <iostream>

int main()
{
    const char *s = "Hello";

    const char * &reference_to_s = s;

    std::cout << reference_to_s << '\n';
}

The same program can be rewritten also the following way

#include <iostream>

using T = const char *;

int main()
{
    T s = "Hello";

    T & reference_to_s = s;

    std::cout << reference_to_s << '\n';
}

Thus the parameters of the function swap

void swap(char * &str1, char * &str2); 

are references to pointers to non-constant strings/arrays.

In the first call there is an attempt to swap values of two pointers that are passed by reference.

However this call

swap(str1, str2); 

is incorrect because the arguments have the type const char * while the parameters declared without the qualifier const.

Using the alias declaration shown above your program can be written like

#include <iostream>

using T = const char *;

void swap( T &s1, T &s2 )
{
    T temp = s1;
    s1 = s2;
    s2 = temp;
}

int main()
{
    T str1 = "GEEKS"; 
    T str2 = "FOR GEEKS"; 

    std::cout << "str1 is " << str1 << '\n'; 
    std::cout << "str2 is " << str2 << '\n';
    std::cout << '\n';

    swap( str1, str2 ); 

    std::cout << "str1 is " << str1 << '\n'; 
    std::cout << "str2 is " << str2 << '\n'; 
    std::cout << '\n';
}

Its output is

str1 is GEEKS
str2 is FOR GEEKS

str1 is FOR GEEKS
str2 is GEEKS

The next step to make references more clear is substitute the alias declaration and the non-template function swap for a template function swap.

#include <iostream>

template <typename T>
void swap( T &s1, T &s2 )
{
    T temp = s1;
    s1 = s2;
    s2 = temp;
}

int main()
{
    const char *str1 = "GEEKS"; 
    const char *str2 = "FOR GEEKS"; 

    std::cout << "str1 is " << str1 << '\n'; 
    std::cout << "str2 is " << str2 << '\n';
    std::cout << '\n';

    swap( str1, str2 ); 

    std::cout << "str1 is " << str1 << '\n'; 
    std::cout << "str2 is " << str2 << '\n'; 
    std::cout << '\n';

    char c1 = 'A';
    char c2 = 'Z';

    std::cout << "c1 is " << c1 << '\n'; 
    std::cout << "x2 is " << c2 << '\n'; 
    std::cout << '\n';

    swap( c1, c2 );

    std::cout << "c1 is " << c1 << '\n'; 
    std::cout << "x2 is " << c2 << '\n'; 
    std::cout << '\n';
}

The program output is

str1 is GEEKS
str2 is FOR GEEKS

str1 is FOR GEEKS
str2 is GEEKS

c1 is A
x2 is Z

c1 is Z
x2 is A

So in the first call of swap the referenced type is const char *. In the second call of swapthe referenced type is char.

Upvotes: 3

Adrian Mole
Adrian Mole

Reputation: 51825

Passing a reference to a pointer is much like passing a reference to any other type of variable. So, in the function:

void swap(char * &str1, char * &str2) {
\\..

the types of the two arguments are char* (pointer-to-characters, or C-style strings).

In reality, the reference is actually the address of each argument so, when the function 'swaps' the pointers, the swapping is also effective in the calling code.

If the arguments were simply char* (rather than char* &), then the 'pointers' passed would be copies of their values in the calling code, and anything done on/with them in the function would have no effect in that calling code. (But note: the function can still change the data pointed to by the arguments - it just can't change/modify the actual pointers, as it needs to!)

However, in your 'suggested alternative', where you have:

void swap(char &str1, char &str2) {
//..

you are changing the actual type of the arguments! Here, you are passing references to (i.e. addresses of) single characters (char variables), rather than the (start addresses of) character strings.

Upvotes: 1

Jesper Juhl
Jesper Juhl

Reputation: 31465

It's a reference to a pointer. That way the function can access not only what the pointer points to, but can also modify the passed in pointer itself (it can change what the passed in pointer points to, so it points to something else).

Upvotes: 2

Related Questions