Pointer to Pointer

 A pointer to pointer in C is essentially a pointer that stores the address of another pointer. It allows us to work with pointers on multiple levels, which is useful in cases where we need to dynamically allocate memory or pass pointers to functions that modify the original data.

Understanding Pointer to Pointer (**)

To understand the basics, let’s break down a simple example:

#include <stdio.h>

int main() {

int x = 10; // A simple integer variable
int *p = &x; // p is a pointer to x
int **pp = &p; // pp is a pointer to p (a pointer to pointer)

printf("Value of x: %d\n", x);
printf("Value of *p (x): %d\n", *p);
printf("Value of **pp (x): %d\n", **pp);

return 0;

}

In this example:

  • x is an integer with a value of 10.
  • p is a pointer that stores the address of x (using &x).
  • pp is a pointer to a pointer, holding the address of p.

When we print **pp, it first dereferences pp to get the address stored in p, and then dereferences p to get the value stored in x. So **pp ultimately gives us the value of x.

Why Use Pointer to Pointer?

Pointers to pointers are especially useful in these situations:

  1. Dynamic Memory Allocation for Multidimensional Arrays:

    We can use a pointer to pointer to create arrays of arrays (e.g., 2D arrays) with dynamic memory allocation.

  2. Passing a Pointer to a Function and Modifying It:

    When we need a function to modify the value of a pointer (such as reallocating memory or updating the pointer to point somewhere else), we use a pointer to pointer.

  3. Working with Arrays of Strings:

    An array of strings (array of char * pointers) can be represented using char **, which is helpful in handling lists of strings, like command-line arguments.

Examples of Pointer to Pointer Usage

1. Dynamic Memory Allocation for a 2D Array

Let’s say we want to create a 2D array dynamically. Using a pointer to pointer allows us to create an array of arrays with flexible memory allocation.

#include <stdio.h>
#include <stdlib.h>

int main() {

int rows = 3, cols = 4;
int **arr;

// Allocate memory for an array of pointers (rows)
arr = (int **)malloc(rows * sizeof(int *));

// Allocate memory for each row (columns)
for (int i = 0; i < rows; i++) {
arr[i] = (int *)malloc(cols * sizeof(int));
}

// Initialize and print the array

for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
    arr[i][j] = i + j; // Sample initialization

printf("%d ", arr[i][j]);
}

printf("\n");

}



// Free allocated memory

for (int i = 0; i < rows; i++) {
free(arr[i]); // Free each row
}

free(arr); // Free the array of pointers
return 0;
}

Here:

  • arr is a pointer to pointer (int **) that holds the addresses of rows.
  • We allocate memory for each row separately, giving us flexibility in the size of each row.
  • Finally, we free each row and then the array of row pointers.

2. Modifying a Pointer in a Function

Suppose we want to modify a pointer from inside a function. Using a pointer to pointer allows us to directly change the original pointer’s value.

#include <stdio.h>
#include <stdlib.h>

void allocate_memory(int **p) {

// Allocate memory for an integer and store the address in *p
*p = (int *)malloc(sizeof(int));

if (*p != NULL) {
**p = 20; // Set the allocated integer to 20
}
}

int main() {

int *ptr = NULL;
allocate_memory(&ptr); // Pass the address of ptr

if (ptr != NULL) {
printf("Allocated value: %d\n", *ptr);
free(ptr); // Free the allocated memory
}

return 0;
}

In this example:

  • We pass &ptr to allocate_memory, which means p is a pointer to ptr (a pointer to pointer).
  • Inside the function, *p = (int *)malloc(sizeof(int)) allocates memory and assigns it to ptr.
  • We can then set the value in this allocated space and print it in the main function.

3. Array of Strings

An array of strings can be implemented as a char ** because each element is a char * (pointer to a string).

#include <stdio.h>
int main() {

const char *colors[] = {"Red", "Green", "Blue", "Yellow"};
char **p = colors; // p is a pointer to pointer to char

for (int i = 0; i < 4; i++) {
printf("Color %d: %s\n", i, *(p + i));
}
return 0;

}

In this example:

  • colors is an array of char * strings, and p points to the first element of colors.
  • *(p + i) gives each string (color name) by dereferencing the pointer to pointer.

Summary

  • A pointer to pointer (**) allows us to reference another pointer.
  • It is useful for:
    • Dynamic memory allocation in multidimensional arrays.
    • Modifying a pointer inside a function.
    • Handling arrays of strings or lists.

Using pointer to pointer gives us control over complex data structures and helps manage memory effectively in C


Comments

Popular posts from this blog

Programming in C GXEST204 - KTU 2024 scheme syllabus notes pdf ------- Dr Binu V P

Structure of a C Program

Single and Multi Dimensional Arrays