Pointer to Pointer in C: Double Pointer

Introduction


Pointer to Pointer in C: Double Pointer


In C programming, pointers provide direct memory access and manipulation capabilities. While a standard pointer stores the address of a variable, a pointer to pointer—also known as a double pointer—stores the address of another pointer variable. This concept introduces an additional level of indirection, enabling more complex data structures and dynamic memory management techniques.


Understanding double pointers is essential for working with multi-dimensional arrays, modifying pointer arguments within functions, and implementing data structures such as linked lists and trees. In this article, you will gain an understanding of how double pointers function, how to declare and initialize them, and how multiple levels of indirection operate within memory.


(toc) #title=(Table of Content)


What Is a Pointer to Pointer?


A pointer to pointer is a variable that stores the memory address of another pointer variable. Whereas a single-level pointer points to a standard data variable (such as an integer or float), a double pointer points to a pointer variable. This creates a two-step chain of references.


Memory Representation of Single Pointer


Consider a standard integer variable declared and initialized:


\[ \text{int a = 10;} \]


In memory, variable a occupies four bytes (on a 32-bit system) containing the value 10. Its memory address might be 0x1000.


A pointer variable intended to store the address of a is declared as:


\[ \text{int *p = &a;} \]


Here, p stores the address 0x1000. The pointer p itself resides at a different memory location, such as 0x850.


Memory Representation of Single Pointer


Declaring a Double Pointer


To declare a pointer that stores the address of another pointer variable, use two asterisks:


\[ \text{int **q = &p;} \]


The declaration reads from right to left: q is a pointer to a pointer to an integer. Variable q stores the address of p (0x850), and q itself occupies its own memory location, such as 0x1046.


Types and Levels of Pointers


Pointers are categorized by their indirection level:


Pointer Level Declaration Stores Address Of Example
Zero-level (variable) int a; N/A (stores value) a = 10;
One-level pointer int *p; Zero-level variable p = &a;
Two-level pointer (double) int **q; One-level pointer q = &p;
Three-level pointer int ***r; Two-level pointer r = &q;

Each additional asterisk adds one level of indirection. The data type specification (int) indicates the ultimate data type being pointed to after all dereferences.


Accessing Values Through Multiple Indirections


To retrieve the original integer value through different pointer levels, apply the dereference operator (*) repeatedly:


  • Using the variable directly: a
  • Using a single pointer: *p
  • Using a double pointer: **q
  • Using a triple pointer: ***r

Original Example


Consider a chain of pointers:


c

int a = 10;
int *p = &a;    // p holds address of a
int **q = &p;   // q holds address of p
int ***r = &q;  // r holds address of q


To access the value 10 through r:


\[ ***r = **q = *p = a = 10 \]


The dereference operation proceeds stepwise: *r yields the address stored in r (which points to q). **r dereferences again to reach p. ***r dereferences a third time to reach a.


Accessing Values Through Multiple Indirections


Practical Code Example


c

#include <stdio.h>

int main() {
    int a = 10;
    int *p = &a;
    int **q = &p;
    int ***r = &q;
    
    // Three methods to print the same value
    printf("Value of a: %d\n", a);
    printf("Using single pointer *p: %d\n", *p);
    printf("Using double pointer **q: %d\n", **q);
    printf("Using triple pointer ***r: %d\n", ***r);
    
    // Printing addresses
    printf("Address of a: %p\n", &a);
    printf("Address of p (stored in q): %p\n", q);
    printf("Address of q (stored in r): %p\n", r);
    
    // Modifying value through double pointer
    **q = 25;
    printf("After **q = 25, a = %d\n", a);
    
    // Modifying value through triple pointer
    ***r = 78;
    printf("After ***r = 78, a = %d\n", a);
    
    return 0;
}


Valid and Invalid Assignments


Type compatibility is critical when working with multi-level pointers. The compiler enforces these rules strictly:


Assignment Validity Reason
int *p = &a; Valid One-level pointer stores address of zero-level variable
int **q = &p; Valid Two-level pointer stores address of one-level pointer
int **q = &a; Invalid Two-level pointer cannot store address of zero-level variable
int ***r = &q; Valid Three-level pointer stores address of two-level pointer
int ***r = &p; Invalid Three-level pointer cannot store address of one-level pointer

The rule follows a consistent pattern: an N-level pointer must store the address of an (N-1)-level pointer.


Common Errors to Avoid


Attempting to Assign Integer Values to Pointer Addresses


The following code produces a compilation error:


What happens when writing *q = 25 with a double pointer?

The compiler generates an "incompatible type" error because *q yields a pointer value, and assigning an integer to a pointer is illegal.



Can a double pointer store the address of a regular integer variable?

No. A double pointer must store the address of a single pointer variable; storing the address of an integer causes an incompatible pointer type warning or error.



How many dereference operators are needed for an N-level pointer?

Exactly N dereference operators are required to access the ultimate value from an N-level pointer.



What is the size of a pointer on a 32-bit system?

Pointers occupy 4 bytes on a 32-bit system regardless of the indirection level.



Conclusion


Pointer to pointer concepts enable sophisticated memory management patterns in C programming. By storing addresses of other pointers, developers can implement dynamic multi-dimensional arrays, modify pointer arguments within functions, and construct complex linked data structures. The key principles to remember are type compatibility across indirection levels and the relationship between the number of asterisks in declaration and dereference operations. As systems programming continues to demand efficient memory handling, proficiency with multi-level pointers remains a foundational skill for C developers.


#buttons=(Ok, Go it!) #days=(20)

Our website uses cookies to enhance your experience. Learn More
Ok, Go it!