2

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; 
} 
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Phineas
  • 159
  • 2
  • 10
  • 3
    Does this answer your question? [Meaning of \*& and \*\*& in C++](https://stackoverflow.com/questions/5789806/meaning-of-and-in-c) – Yksisarvinen Jan 19 '20 at 15:23
  • It depends what you need. `char&` is a reference to a `char` whereas `char*&` is a reference to a `char` pointer. Very different things. – Sami Kuhmonen Jan 19 '20 at 15:23
  • @Yksisarvinen I have already read this and it's a bit advanced for me, basically I want to understand why not just use `&`. In what situation `*&` is better than `&`. – Phineas Jan 19 '20 at 15:30
  • @Phineas Your type is `char*`, not `char`, so the reference to this type is `char* &`, not `char &`. There is no "in what situation one is better". For a given type you use given syntax, that's all. – Yksisarvinen Jan 19 '20 at 15:35

4 Answers4

3

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.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

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).

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
2

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.

Kalloax
  • 21
  • 2
1

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.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • I'm curious why do they output the same results? – Phineas Jan 19 '20 at 15:41
  • @Phineas And I'm curious why the second version even compiles! – Adrian Mole Jan 19 '20 at 15:51
  • @Phineas ... unless, of course, you have **both** function definitions in your code, in which case you have what's known as *overloading* - and the compiler will use the one that (best) matches the call, which will be the 'original' one, in your case (so the second function isn't even used). – Adrian Mole Jan 19 '20 at 15:54
  • nope, perfectly fine, only 1 function, compiled on Visual Studio. (http://cpp.sh/3pie4) – Phineas Jan 19 '20 at 16:09
  • 1
    @Phineas Your problem lies with the line `using namespace std;` - this defines its own `swap` function which is being used in place of the one you provide. See here: [Why is “using namespace std;” considered bad practice?](https://stackoverflow.com/q/1452721/10871073). – Adrian Mole Jan 19 '20 at 16:19
  • Add a `std::cout << "My function" << std::endl;` line in your function, and you will see that it is never called. @Phineas – Adrian Mole Jan 19 '20 at 16:20
  • yes, I've just realized, it uses the its `std::swap`. Thanks a lot – Phineas Jan 19 '20 at 16:23