C++ Pointers to Pointers

Introduction

Pointers to pointers (double pointers) in C++ are used to store the address of another pointer. This level of indirection can be useful in various scenarios, such as managing dynamic memory for multi-dimensional arrays, passing pointers to functions that need to modify the pointer itself, and handling complex data structures.

Defining and Using Pointers to Pointers

Basic Example

To define a pointer to a pointer, use the following syntax:

type** ptr;

Example: Pointer to a Pointer

#include <iostream>
using namespace std;

int main() {
    int value = 42;
    int* ptr = &value;       // Pointer to int
    int** ptrPtr = &ptr;     // Pointer to pointer to int

    // Accessing the value using pointers
    cout << "Value: " << value << endl;
    cout << "Value through ptr: " << *ptr << endl;
    cout << "Value through ptrPtr: " << **ptrPtr << endl;

    // Modifying the value using pointers
    **ptrPtr = 100;
    cout << "Modified value: " << value << endl;

    return 0;
}

Output

Value: 42
Value through ptr: 42
Value through ptrPtr: 42
Modified value: 100

Explanation

  • int* ptr = &value; defines a pointer ptr that points to value.
  • int** ptrPtr = &ptr; defines a pointer to a pointer ptrPtr that points to ptr.
  • **ptrPtr accesses the value of value through two levels of indirection.
  • Modifying **ptrPtr changes the value of value.

Dynamic Memory Allocation for Multi-dimensional Arrays

Pointers to pointers are often used to dynamically allocate memory for 2D arrays.

Example: Dynamic 2D Array Allocation

#include <iostream>
using namespace std;

int main() {
    int rows = 3, cols = 3;

    // Allocate memory for a 2D array
    int** matrix = new int*[rows];
    for (int i = 0; i < rows; i++) {
        matrix[i] = new int[cols];
    }

    // Initialize the 2D array
    int value = 1;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = value++;
        }
    }

    // Print the 2D array
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cout << matrix[i][j] << " ";
        }
        cout << endl;
    }

    // Deallocate memory
    for (int i = 0; i < rows; i++) {
        delete[] matrix[i];
    }
    delete[] matrix;

    return 0;
}

Output

1 2 3
4 5 6
7 8 9

Explanation

  • int** matrix = new int*[rows]; allocates memory for an array of pointers.
  • The loop for (int i = 0; i < rows; i++) { matrix[i] = new int[cols]; } allocates memory for each row.
  • The nested loops initialize and print the 2D array.
  • The memory is deallocated using delete[] for each row and then for the array of pointers.

Passing Pointers to Pointers to Functions

Passing pointers to pointers to functions allows the function to modify the original pointer.

Example: Modifying a Pointer in a Function

#include <iostream>
using namespace std;

// Function to allocate memory and assign a value
void allocateAndAssign(int** ptr, int value) {
    *ptr = new int;
    **ptr = value;
}

int main() {
    int* ptr = nullptr;

    // Allocate memory and assign a value through the function
    allocateAndAssign(&ptr, 42);

    // Print the assigned value
    cout << "Value: " << *ptr << endl;

    // Deallocate memory
    delete ptr;

    return 0;
}

Output

Value: 42

Explanation

  • The function allocateAndAssign(int** ptr, int value) takes a pointer to a pointer as an argument.
  • *ptr = new int; allocates memory for an integer and assigns the address to the pointer.
  • **ptr = value; assigns the value to the allocated memory.
  • The original pointer is modified by the function, and the assigned value is printed in main.

Example Programs

Example 1: Managing a Dynamic 2D Array with Functions

#include <iostream>
using namespace std;

// Function to allocate memory for a 2D array
int** allocate2DArray(int rows, int cols) {
    int** array = new int*[rows];
    for (int i = 0; i < rows; i++) {
        array[i] = new int[cols];
    }
    return array;
}

// Function to deallocate memory for a 2D array
void deallocate2DArray(int** array, int rows) {
    for (int i = 0; i < rows; i++) {
        delete[] array[i];
    }
    delete[] array;
}

int main() {
    int rows = 3, cols = 3;

    // Allocate memory for a 2D array
    int** matrix = allocate2DArray(rows, cols);

    // Initialize the 2D array
    int value = 1;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = value++;
        }
    }

    // Print the 2D array
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cout << matrix[i][j] << " ";
        }
        cout << endl;
    }

    // Deallocate memory
    deallocate2DArray(matrix, rows);

    return 0;
}

Output

1 2 3
4 5 6
7 8 9

Explanation

  • The allocate2DArray function allocates memory for a 2D array and returns a pointer to the array.
  • The deallocate2DArray function deallocates the memory for the 2D array.
  • The 2D array is initialized, printed, and deallocated in the main function.

Example 2: Dynamic 3D Array Allocation and Deallocation

#include <iostream>
using namespace std;

// Function to allocate memory for a 3D array
int*** allocate3DArray(int rows, int cols, int depth) {
    int*** array = new int**[rows];
    for (int i = 0; i < rows; i++) {
        array[i] = new int*[cols];
        for (int j = 0; j < cols; j++) {
            array[i][j] = new int[depth];
        }
    }
    return array;
}

// Function to deallocate memory for a 3D array
void deallocate3DArray(int*** array, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            delete[] array[i][j];
        }
        delete[] array[i];
    }
    delete[] array;
}

int main() {
    int rows = 2, cols = 2, depth = 2;

    // Allocate memory for a 3D array
    int*** array = allocate3DArray(rows, cols, depth);

    // Initialize the 3D array
    int value = 1;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            for (int k = 0; k < depth; k++) {
                array[i][j][k] = value++;
            }
        }
    }

    // Print the 3D array
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            for (int k = 0; k < depth; k++) {
                cout << "Element [" << i << "][" << j << "][" << k << "]: " << array[i][j][k] << endl;
            }
        }
    }

    // Deallocate memory
    deallocate3DArray(array, rows, cols);

    return 0;
}

Output

Element [0][0][0]: 1
Element [0][0][1]: 2
Element [0][1][0]: 3
Element [0][1][1]: 4
Element [1][0][0]: 5
Element [1][0][1]: 6
Element [1][1][0]: 7
Element [1][1][1]: 8

Explanation

  • The allocate3DArray function allocates memory for a 3D array and returns a pointer

to the array.

  • The deallocate3DArray function deallocates the memory for the 3D array.
  • The 3D array is initialized, printed, and deallocated in the main function.

Conclusion

Pointers to pointers in C++ provide a powerful way to manage dynamic memory allocation for multi-dimensional arrays, modify pointers through functions, and handle complex data structures. This chapter covered the basics of defining and using pointers to pointers, dynamic memory allocation for 2D and 3D arrays, and passing pointers to pointers to functions. Example programs demonstrated practical applications of pointers to pointers, including managing dynamic 2D and 3D arrays and modifying pointers in functions. Understanding how to use pointers to pointers effectively is essential for writing efficient and flexible C++ programs.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top