Multiple Level Pointers Or Chain Of Pointers

Introduction to Multiple Level Pointers in C++:

Multiple level pointers, also known as pointers to pointers to pointers (and so on), extend the concept of pointers to allow indirect access to memory locations. Each additional level of indirection adds another layer of abstraction, enabling more complex memory management scenarios. Multiple level pointers are commonly used in situations where you need to dynamically allocate and manipulate multi-dimensional arrays or create complex data structures like linked lists of pointers.

Key Points:

  1. Levels of Indirection:
    • Multiple level pointers introduce multiple levels of indirection, where each level points to the memory address of the next level.
  2. Dynamic Memory Allocation:
    • Multiple level pointers are often used in dynamic memory allocation scenarios where you need to allocate memory for complex data structures with nested pointers.
  3. Passing Arguments to Functions:
    • Multiple level pointers can be passed as arguments to functions, allowing functions to modify the original pointer variables or allocate memory dynamically.
  4. Error Handling:
    • In error handling situations, multiple level pointers can be used to return error codes or indicate success or failure.

Example C++ Program:

Here’s an example program that demonstrates the usage of multiple level pointers with line-by-line explanations:

#include <iostream>
using namespace std;

// Function to allocate memory for a 2D array using multiple level pointers
int*** allocateMemory(int rows, int cols) {
    int ***arr = new int**[rows]; // Allocate memory for array of pointers to pointers
    for (int i = 0; i < rows; ++i) {
        arr[i] = new int*[cols]; // Allocate memory for array of pointers for each row
        for (int j = 0; j < cols; ++j) {
            arr[i][j] = new int; // Allocate memory for each element
        }
    }
    return arr; // Return pointer to pointer to pointer
}

int main() {
    int rows = 2, cols = 3;
    
    // Allocate memory for a 2D array
    int ***matrix = allocateMemory(rows, cols);
    
    // Initialize values
    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
    cout << "Matrix:" << endl;
    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) {
        for (int j = 0; j < cols; ++j) {
            delete *(matrix[i] + j); // Deallocate memory for each element
        }
        delete[] matrix[i]; // Deallocate memory for array of pointers for each row
    }
    delete[] matrix; // Deallocate memory for array of pointers to pointers

    return 0;
}

Explanation:

  1. allocateMemory Function:
    • The allocateMemory function dynamically allocates memory for a 2D array of integers using multiple level pointers.
    • It takes the number of rows and columns as parameters.
    • Inside the function, memory is first allocated for an array of pointers to pointers (arr) to hold the rows.
    • Then, memory is allocated for an array of pointers for each row.
    • Finally, memory is allocated for each individual element of the 2D array.
  2. main Function:
    • In the main function, define variables rows and cols to specify the dimensions of the 2D array.
    • Call the allocateMemory function to allocate memory for the 2D array.
    • Initialize the values of the 2D array in a sequential manner.
    • Print the contents of the 2D array using nested loops.
    • Deallocate the dynamically allocated memory for each element, row, and the array of pointers to pointers using delete[].

This example demonstrates how multiple level pointers can be used to dynamically allocate memory for a 2D array and manipulate its contents efficiently in C++.

Given below are few more examples to explain chain of pointers in C++

#include <iostream>

int main() {
    int x = 5;
    int *ptr1 = &x;
    int **ptr2 = &ptr1;

    std::cout << "Value of x: " << x << std::endl;
    std::cout << "Value of x through ptr1: " << *ptr1 << std::endl;
    std::cout << "Value of x through ptr2: " << **ptr2 << std::endl;

    return 0;
}

Explanation:

  • int x = 5;: Declares an integer variable x and initializes it to 5.
  • int *ptr1 = &x;: Declares a pointer ptr1 that points to the address of x.
  • int **ptr2 = &ptr1;: Declares a pointer ptr2 that points to the address of ptr1.
  • *ptr1 dereferences ptr1, giving the value of x. **ptr2 dereferences ptr2 and then dereferences the result, giving the value of x.
  • Outputs the values of x using direct access, ptr1, and ptr2.

This program demonstrates a basic example of a chain of pointers.

Chain of Pointers – Dynamic Memory Allocation

Introduction: This program demonstrates a chain of pointers with dynamic memory allocation.

#include <iostream>

int main() {
    int x = 5;
    int *ptr1 = new int;
    *ptr1 = x;
    int **ptr2 = new int*;
    *ptr2 = ptr1;

    std::cout << "Value of x: " << x << std::endl;
    std::cout << "Value of x through ptr1: " << *ptr1 << std::endl;
    std::cout << "Value of x through ptr2: " << **ptr2 << std::endl;

    delete ptr1;
    delete ptr2;

    return 0;
}

Explanation:

  • int x = 5;: Declares an integer variable x and initializes it to 5.
  • int *ptr1 = new int;: Dynamically allocates memory for an integer and assigns the address to ptr1.
  • *ptr1 = x;: Assigns the value of x to the memory location pointed to by ptr1.
  • int **ptr2 = new int*;: Dynamically allocates memory for an integer pointer and assigns the address to ptr2.
  • *ptr2 = ptr1;: Assigns the value of ptr1 to the memory location pointed to by ptr2.
  • Outputs the values of x using direct access, ptr1, and ptr2.
  • Deallocates the dynamically allocated memory.

This program demonstrates a chain of pointers with dynamic memory allocation.

Chain of Pointers – Linked List

Introduction: This program demonstrates a chain of pointers to implement a simple linked list.

#include <iostream>

struct Node {
    int data;
    Node* next;
};

int main() {
    Node* head = nullptr;
    Node* second = nullptr;
    Node* third = nullptr;

    // Allocate memory for nodes
    head = new Node;
    second = new Node;
    third = new Node;

    // Assign data and pointers
    head->data = 1;
    head->next = second;
    second->data = 2;
    second->next = third;
    third->data = 3;
    third->next = nullptr;

    // Traverse and print linked list
    Node* current = head;
    while (current != nullptr) {
        std::cout << current->data << " ";
        current = current->next;
    }
    std::cout << std::endl;

    // Deallocate memory
    delete head;
    delete second;
    delete third;

    return 0;
}

Explanation:

  • struct Node: Defines a structure for a node of the linked list containing an integer data and a pointer to the next node.
  • Node* head = nullptr;, Node* second = nullptr;, Node* third = nullptr;: Declare pointers to nodes and initialize them to nullptr.
  • Allocate memory for nodes using new.
  • Assign data and pointers to create the linked list.
  • Traverse the linked list from the head and print the data of each node.
  • Deallocate memory for the nodes using delete.

This program demonstrates a chain of pointers to implement a simple linked list.

These examples provide a detailed understanding of the chain of pointers in C++.