Pointer to Pointer (Double Pointer) in C

Hello there, aspiring programmers! Today, we're going to embark on an exciting journey into the world of pointers - specifically, pointers to pointers. Now, I know what you might be thinking: "Pointers? Double pointers? This sounds like a nightmare!" But don't worry, I promise to make this as fun and easy to understand as possible. So, grab your favorite beverage, get comfortable, and let's dive in!

C - Pointer to Pointer

What is a Double Pointer in C?

Imagine you're in a treasure hunt. You have a map (let's call it a pointer) that leads you to a chest. But surprise! Inside the chest, there's another map (another pointer) that leads to the actual treasure. That's essentially what a double pointer is - a pointer that points to another pointer.

In C programming, a double pointer is exactly what it sounds like - a pointer to a pointer. It's a variable that stores the address of another pointer. This might sound a bit confusing at first, but don't worry, we'll break it down step by step.

Declaration of Pointer to a Pointer

Let's start with how we declare a double pointer. The syntax is pretty straightforward:

int **ptr;

Here, ptr is a pointer to a pointer to an integer. The first asterisk * makes it a pointer, and the second * makes it a pointer to a pointer.

Example of Pointer to Pointer (Double Pointer)

Let's look at a simple example to understand this better:

#include <stdio.h>

int main() {
    int x = 5;
    int *p = &x;
    int **pp = &p;

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

    return 0;
}

Output:

Value of x: 5
Value of x using p: 5
Value of x using pp: 5

Let's break this down:

  1. We declare an integer x and initialize it with 5.
  2. We create a pointer p that points to x.
  3. We create a double pointer pp that points to p.
  4. We then print the value of x in three different ways:
    • Directly using x
    • Using the single pointer p (we dereference it once with *p)
    • Using the double pointer pp (we dereference it twice with **pp)

All three methods give us the same value: 5. It's like reaching the treasure using different maps!

How Does a Normal Pointer Work in C?

Before we dive deeper into double pointers, let's quickly review how normal pointers work:

int y = 10;
int *q = &y;

printf("Value of y: %d\n", y);
printf("Address of y: %p\n", (void*)&y);
printf("Value of q: %p\n", (void*)q);
printf("Value pointed by q: %d\n", *q);

Output:

Value of y: 10
Address of y: 0x7ffd5e8e9f44
Value of q: 0x7ffd5e8e9f44
Value pointed by q: 10

Here, q is a pointer that stores the address of y. When we use *q, we're accessing the value stored at that address.

How Does a Double Pointer Work?

Now, let's extend this to double pointers:

int z = 15;
int *r = &z;
int **rr = &r;

printf("Value of z: %d\n", z);
printf("Address of z: %p\n", (void*)&z);
printf("Value of r: %p\n", (void*)r);
printf("Address of r: %p\n", (void*)&r);
printf("Value of rr: %p\n", (void*)rr);
printf("Value pointed by r: %d\n", *r);
printf("Value pointed by rr: %p\n", (void*)*rr);
printf("Value pointed by pointed value of rr: %d\n", **rr);

Output:

Value of z: 15
Address of z: 0x7ffd5e8e9f48
Value of r: 0x7ffd5e8e9f48
Address of r: 0x7ffd5e8e9f50
Value of rr: 0x7ffd5e8e9f50
Value pointed by r: 15
Value pointed by rr: 0x7ffd5e8e9f48
Value pointed by pointed value of rr: 15

This might look a bit overwhelming, but let's break it down:

  1. z is an integer with value 15.
  2. r is a pointer that stores the address of z.
  3. rr is a double pointer that stores the address of r.
  4. *r gives us the value of z (15).
  5. *rr gives us the value of r (which is the address of z).
  6. **rr gives us the value of z (15).

Think of it like this: rr points to r, which points to z. So **rr is like saying "follow the first pointer, then follow the second pointer, and give me the value there".

A Double Pointer Behaves Just Like a Normal Pointer

Here's a little secret: a double pointer is just a pointer, but instead of pointing to an int or a float, it points to another pointer. This means we can do all the same things with double pointers that we can do with normal pointers.

For example, we can use double pointers with arrays:

int main() {
    char *fruits[] = {"Apple", "Banana", "Cherry"};
    char **ptr = fruits;

    for(int i = 0; i < 3; i++) {
        printf("%s\n", *ptr);
        ptr++;
    }

    return 0;
}

Output:

Apple
Banana
Cherry

In this example, fruits is an array of pointers (each pointing to a string), and ptr is a pointer to a pointer to a char (which can point to elements of fruits).

Multilevel Pointers in C (Is a Triple Pointer Possible?)

Yes, you can have triple pointers, quadruple pointers, and so on! There's no theoretical limit to the levels of indirection you can have. However, in practice, it's rare to see more than double pointers.

Here's an example of a triple pointer:

int x = 5;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;

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

Output:

Value of x: 5

But remember, just because you can doesn't mean you should. Multiple levels of indirection can make code harder to read and maintain. As the old programming adage goes, "All problems in computer science can be solved by another level of indirection... except for the problem of too many levels of indirection!"

Conclusion

Congratulations! You've just navigated the tricky waters of double pointers in C. Remember, like many concepts in programming, pointers to pointers might seem confusing at first, but with practice, they'll become second nature.

Here's a table summarizing the key points we've covered:

Concept Syntax Description
Normal Pointer int *p; Points to an integer
Double Pointer int **pp; Points to a pointer to an integer
Dereferencing *p Accesses the value pointed to by p
Double Dereferencing **pp Accesses the value pointed to by the pointer that pp points to
Address-of Operator &x Gets the address of x

Keep practicing, stay curious, and remember - every expert was once a beginner. Happy coding!

Credits: Image by storyset