Functionality and Difference Between *& and **& in C++

Haider Ali Dec 22, 2023
  1. Understanding Pointers and References in C++
  2. * and & Operators in C++
  3. Functionality and Difference Between *& and **& in C++
  4. Handle Values by Pointer in C++
  5. Handle Values by Reference Pointer in C++
  6. Handle Values by Pointer to Pointer Reference (Double Pointer) in C++
  7. Conclusion
Functionality and Difference Between *& and **& in C++

In C++, the symbols *& and **& might seem obscure at first glance, but they play crucial roles in understanding pointers, references, and memory management within the language. These symbols are fundamental to manipulating memory addresses and dealing with complex data structures.

This guide explains the difference and the functionality of *& and **& in C++. To understand these symbols, you need to be familiar with the concept of pointers in C++.

So, before you go ahead and read the whole guide, visit the guide about pointers. Once you have understood this concept, it’ll be easy to understand this guide.

Understanding Pointers and References in C++

Pointers

In C++, a pointer is a variable that holds the memory address of another variable. It allows direct manipulation of memory and is denoted by the asterisk (*) symbol.

For example:

int x = 10;
int *ptr = &x;  // ptr stores the address of x

Here, *& is not explicitly used, but it sets the foundation for understanding the symbols’ significance.

References

References in C++ provide an alias to an existing variable. They are declared using the ampersand (&) symbol and must be initialized during declaration.

For instance:

int y = 20;
int &ref = y;  // ref is a reference to y

This way, *& comes into play indirectly, as references inherently involve memory addresses and dereferencing.

* and & Operators in C++

* (Dereference Operator)

The asterisk (*) operator in C++ is commonly known as the dereference operator. It is used to access the value pointed to by a pointer.

For example:

int z = *ptr;  // z now holds the value of x through dereferencing ptr

& (Address-Of Operator)

The ampersand (&) operator in C++ returns the memory address of a variable. For instance:

int *newPtr = &z;  // newPtr now holds the address of z

*& in C++

Now, let’s explore the use of *& in C++. This combination involves a pointer and a reference and is essential in certain scenarios where manipulation of references via pointers is necessary.

Consider the following example:

int a = 30;
int *ptrA = &a;  // ptrA stores the address of a

int &refA = *ptrA;  // refA is a reference to the value pointed to by ptrA

In this code snippet, *& is utilized to create a reference (refA) that refers to the value stored at the memory location pointed to by ptrA. This combination of pointers and references can be particularly useful in complex data structures and functions that require memory address manipulation.

**& in C++

The **& combination is an advanced use case that involves a pointer to a reference. This scenario is less common but can be encountered in scenarios demanding complex pointer manipulation.

Consider this example:

int b = 40;
int *ptrB = &b;  // ptrB stores the address of b

int **ptrToPtrB = &ptrB;  // ptrToPtrB stores the address of ptrB

Here, **& involves a pointer to a pointer (ptrToPtrB) that stores the address of another pointer (ptrB). This concept is crucial in scenarios where multiple levels of indirection are required, such as handling dynamic memory allocation or working with multi-dimensional arrays.

Functionality and Difference Between *& and **& in C++

In C++, the difference between *& and **& lies in their respective purposes and the level of indirection they represent when working with pointers and references.

*& in C++

  • Purpose: *& involves a pointer to a reference or a reference to a pointer. It combines the concepts of pointers and references, allowing manipulation of references via pointers or vice versa.

  • Usage Example:

    int a = 10;
    int *ptrA = &a;  // ptrA stores the address of a
    
    int &refA = *ptrA;  // refA is a reference to the value pointed to by ptrA
    
  • Functionality: Here, *& allows the creation of a reference (refA) that refers to the value stored at the memory location pointed to by ptrA. It’s commonly used to access the value pointed to by a pointer through a reference.

**& in C++

  • Purpose: **& involves a pointer to a pointer, often used for handling multiple levels of indirection or managing dynamic memory allocation.

  • Usage Example:

    int b = 20;
    int *ptrB = &b;  // ptrB stores the address of b
    
    int **ptrToPtrB = &ptrB;  // ptrToPtrB stores the address of ptrB
    
  • Functionality: Here, **& creates a pointer (ptrToPtrB) that holds the address of another pointer (ptrB). This is useful in scenarios where multiple levels of indirection are required, such as working with dynamic memory allocation, multi-dimensional arrays, or complex data structures.

Key Differences

  • Level of Indirection: *& involves a single level of indirection, either a pointer to a reference or a reference to a pointer. Conversely, **& involves two levels of indirection, a pointer to a pointer.
  • Use Cases: *& is commonly used when a reference needs to be created based on the value pointed to by a pointer. Meanwhile, **& is used when handling scenarios requiring multiple levels of indirection, such as managing pointers to pointers or dynamic memory allocation.

Understanding the distinctions between *& and **& is crucial for effectively managing pointers, references, and multi-level memory indirection in C++, enabling programmers to work with complex data structures and memory allocation efficiently.

When we look to handle values by pointer, we use a pointer. Its syntax is *ptr.

Let’s understand this whole concept with the help of the following examples.

#include <iostream>
using namespace std;

// global variables
int value_1 = 10, value_2 = 20, *global_ptr;

We are simply creating two variables, value_1 and value_2, and one global pointer as *global_ptr. Next, we have made three different functions and methods to clarify everything.

Those functions are as follows:

Handle Values by Pointer in C++

// function, which handles values by pointer
void byPointer(int *ptr) {
  *ptr = 5;
  ptr = global_ptr;
  *ptr = 3;
}

The first function handles values by the pointer; as you can see, its parameter is a pointer.

Inside, we are simply overriding the pointer’s value, pointing it to a global pointer, and later overriding its value again. Let’s see the main() function.

int main() {
  // a pointer to value 1
  int *ptrValue_1 = &value_1;

  // a global pointer having an address of value 2

  global_ptr = &value_2;

  // values before calling the function
  cout << "Value_1 = " << value_1 << endl;
  cout << "Value_2 = " << value_2 << endl;

  cout << "ptrValue_1 = " << ptrValue_1 << endl;
  cout << "global_ptr = " << global_ptr << endl;

  byPointer(ptrValue_1);

  // values after calling function
  cout << "Value_1 = " << value_1 << endl;
  cout << "Value_2 = " << value_2 << endl;

  cout << "ptrValue_1 = " << ptrValue_1 << endl;
  cout << "global_ptr = " << global_ptr << endl;
  return 0;
}

First, we created a pointer that points to the address of the first variable. The global pointer is pointing to the address of the second variable.

We are simply passing the pointer ptrValue_1 to the function mentioned above, as you can see that the initial values of variables value_1 and value_2 are 10 and 20, respectively.

But inside the function byPointer(), those values are overridden. The pointer is also pointing to the address of the global pointer, which is pointing to the address of value_2; that’s why both values were changed.

The output of the above code is:

Value_1 = 10
Value_2 = 20
ptrValue_1 = 0x4b8000
global_ptr = 0x4b8004
Value_1 = 5
Value_2 = 3
ptrValue_1 = 0x4b8000
global_ptr = 0x4b8004

As you can see, both variables’ values are changed, but they did not change the address of the pointers. This is because it makes copies of pointers and handles values using the copies in this way of handling values.

That’s why the address remains unchanged. This concept will help you understand further.

Handle Values by Reference Pointer in C++

Now, let’s understand the concept of *& in C++. Take a look at the following code:

// function, which handles values by pointer Reference
void byPointerReference(int*& ptr) {
  *ptr = 40;
  ptr = global_ptr;
  *ptr = 50;
}

In the above method, we pass a reference to a pointer as its parameter. It’ll work the same as the function in which we passed the pointer.

The only difference will be that it will also change the address of the pointers. After the method, the address of the pointers will be the same as the address of the global pointer, according to this code.

int main() {
  // a pointer to value 1
  int *ptrValue_1 = &value_1;

  // a global pointer having the address of value 2

  global_ptr = &value_2;

  // values before calling the function
  cout << "Value_1 = " << value_1 << endl;
  cout << "Value_2 = " << value_2 << endl;

  cout << "ptrValue_1 = " << ptrValue_1 << endl;
  cout << "global_ptr = " << global_ptr << endl;

  byPointerReference(ptrValue_1);

  // values after calling function
  cout << "Value_1 = " << value_1 << endl;
  cout << "Value_2 = " << value_2 << endl;

  cout << "ptrValue_1 = " << ptrValue_1 << endl;
  cout << "global_ptr = " << global_ptr << endl;
  return 0;
}

The idea here is to show you that both the address and the pointer’s value will change. The output of the above code is as follows:

Value_1 = 10
Value_2 = 20
ptrValue_1 = 0x4b8000
global_ptr = 0x4b8004
Value_1 = 40
Value_2 = 50
ptrValue_1 = 0x4b8004
global_ptr = 0x4b8004

Handle Values by Pointer to Pointer Reference (Double Pointer) in C++

It will work the same as the single pointer reference. The only difference is that it is a double-pointer.

For instance, if you pack a gift inside one box and pack the same gift inside the box in another box, eventually, the other person will have the gift. It does not make a difference.

The only difference will be in the syntax. The double-pointer reference goes as follows:

int **ptrToptr = &ptrValue_1;

Let’s take a look at the function/method:

void bypointerPointerReference(int**& ptr) {
  **ptr = 40;
  *ptr = global_ptr;
  **ptr = 50;
}

There’s no difference except for the syntax. The main function will be as follows:

int main() {
  // a double pointer to value 1
  int *ptrValue_1 = &value_1;
  int **ptrToptr = &ptrValue_1;

  // a global pointer having an address of value 2

  global_ptr = &value_2;

  // values before calling the function
  cout << "Value_1 = " << value_1 << endl;
  cout << "Value_2 = " << value_2 << endl;

  cout << "ptrValue_1 = " << ptrValue_1 << endl;
  cout << "global_ptr = " << global_ptr << endl;
  bypointerPointerReference(ptrToptr);

  // values after calling function
  cout << "Value_1 = " << value_1 << endl;
  cout << "Value_2 = " << value_2 << endl;

  cout << "ptrValue_1 = " << ptrValue_1 << endl;
  cout << "global_ptr = " << global_ptr << endl;
  return 0;
}

The code initializes pointers and global variables, then calls a function bypointerPointerReference() with a pointer passed as an argument. It prints the values of global variables and pointers before and after the function call.

However, the actual functionality or changes made inside the function are not provided in the code snippet, impacting the understanding of how the values might change after the function call.

The output will be the same as the previous method.

Value_1 = 10
Value_2 = 20
ptrValue_1 = 0x4b8000
global_ptr = 0x4b8004
Value_1 = 40
Value_2 = 50
ptrValue_1 = 0x4b8004
global_ptr = 0x4b8004

Conclusion

In C++, *& and **& are symbols crucial for handling pointers, references, and memory management.

  • *& combines pointers and references, allowing manipulation of references via pointers or vice versa. It creates references that point to the value stored by a pointer.
  • **& involves a pointer to a pointer, useful for complex scenarios like pointers to pointers or dynamic memory allocation. It deals with multiple levels of indirection, enabling more intricate memory management.

Understanding these symbols requires familiarity with pointers in C++. Mastering them is essential for efficient management of memory, pointers, and references, especially when working with complex data structures.

Author: Haider Ali
Haider Ali avatar Haider Ali avatar

Haider specializes in technical writing. He has a solid background in computer science that allows him to create engaging, original, and compelling technical tutorials. In his free time, he enjoys adding new skills to his repertoire and watching Netflix.

LinkedIn

Related Article - C++ Pointer