Omicron
Omicron

Reputation: 17

Dereferencing double pointer, triple pointers, and so on

Below is a sample program I created to play around with pointers.

#include <iostream>
using namespace std;

void addOne(int** ptr);
void addTwo(int*** ptr);
void addThree(int**** ptr);
void addFour(int***** ptr);

int main()
{
    int* ptr = nullptr; 
    int x = 1; 
    ptr = &x;

    cout << "Original value of x: " << *ptr << endl;

    addOne(&ptr);

    cin.get();
    return 0;
}

void addOne(int** ptr)
{
    **ptr += 1;
    cout << "After adding 1: " << **ptr << endl;
    addTwo(&ptr);
}

void addTwo(int*** ptr)
{
    ***ptr += 2;
    cout << "After adding 2: " << ***ptr << endl;
    addThree(&ptr);
}

void addThree(int**** ptr)
{
    ****ptr += 3;
    cout << "After adding 3: " << ****ptr << endl;
    addFour(&ptr);
}

void addFour(int***** ptr)
{
    *****ptr += 4; 
    cout << "After adding 4: " << *****ptr << endl;
}

The program above will give me the following output:

Original value of x: 1
After adding 1: 2
After adding 2: 4
After adding 3: 7
After adding 4: 11

Now focus on the addFour function:

void addFour(int***** ptr)
{
    *****ptr += 4; 
    cout << "After adding 4: " << *****ptr << endl;
}

Now what I did was I reduced the number of *s in the addFour function by doing this:

void addFour(int***** ptr)
{
   ****ptr += 4; 
   cout << "After adding 4: " << ****ptr << endl;
}

When I did the above code, it gave me the following output:

Original value of x: 1
After adding 1: 2
After adding 2: 4
After adding 3: 7
After adding 4: 010EFDE0

My question then is, what is the following statements doing since I reduced the number of *s:

****ptr += 4; 
cout << "After adding 4: " << ****ptr << endl;

Can someone please explain this for me?

Upvotes: 0

Views: 4525

Answers (4)

Bing Bang
Bing Bang

Reputation: 534

        // if you want to understand pointers this is my fave example

    struct block
        {
        int data;
        struct block *next_block;
        };

    struct block *block_head = NULL;

    add_block(int n) /* add n in the sorted position */
    {
        struct block *new, *prev = NULL, *bp = block_head;

        new = malloc(sizeof(struct block));
        new->data = n;
        while(bp != NULL)
            if(bp->data > n)
            {
                prev = bp;
                bp = bp->next_block;
            }
            else 
            {
                if(prev == NULL)
                {             
                    new->next_block = bp;
                    block_head = new;
                }
                else
                {
                    new->next_block = bp;
                    prev->next_block = new;
                }

    if(block_head == NULL)
        block_head = new;
    else
        {
        prev->next_block = new;
        new->next_block = NULL;
        }
}

// the above is how you usually do a linked list but it's messy and ugly
// not elegant
// the elegant way to do this is with a double pointer

    add_block(int n) /* add n in the sorted position */
    {
        struct block *new,  **bp = &block_head;

        new = malloc(sizeof(struct block));
        new->data = n;
        while(*bp != NULL)
           if((*bp)->data > n)
               bp = &((*bp)->next_block);
           else
               break;
        new->next_block = *bp;
        *bp = new;
}

// if you can understand the elegant version, you probably got pointers down cold.

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385108

You reduced the dereferencing in addFour to four levels, but the function still takes an int*****.

Most of your code is irrelevant and can be reduced to something like this:

int x = 1;

cout << "Original value of x: " << *&x << endl;
x += 1;
cout << "After adding 1: " << **&&x << endl;
x += 2;
cout << "After adding 2: " << ***&&&x << endl;
x += 3;
cout << "After adding 3: " << ****&&&&x << endl;
x += 4;
cout << "After adding 4: " << *****&&&&&x << endl;

So far your dereference and address-of operations cancel out. But then you're asking what this is:

cout << "After adding 4: " << ****&&&&&x << endl;

Quite simply, you have not performed the final dereference so you're left with &x, not x.

And &x is a pointer. In the example above, you'd be seeing the address of x in memory, given in hexadecimal notation. In your case, your ptr has an unspecified value because pointer arithmetic out of bounds of an object has undefined behaviour, but in practice you're printing the value of the address of x plus sizeof(int).

Upvotes: 3

alain
alain

Reputation: 12037

Trying to visualize this graphically, you have:

P -> P -> P -> P -> P -> X

X is the value, P are pointers.
Every time you write &, you move to the left, and every time you write *, you move to the right.

So if you have &&&&&x, and you increment ****x, you do this:

P -> P -> P -> P -> P -> X
                      \
                       > ?

You moved four levels to the right, and incremented the pointer there, which now points to a memory location after X.

Then you print ****x, which is a pointer, because you moved four levels to the right.

Upvotes: 1

Jean-Baptiste Yun&#232;s
Jean-Baptiste Yun&#232;s

Reputation: 36391

addOne receives the address of ptr that points to x and store it into a local variable ptr.

addTwo receives the address of addOne::ptr and store it in its local ptr variable.

addThree receives the address of addTwo::ptr and store it in its local ptr variable.

addFour receives the address of addThree::ptr and store it in its local ptr variable. Thus in addFour (second version):

  • *ptr is addThree::ptr,
  • **ptr is addTwo::ptr,
  • ***ptr is addOne::ptr and
  • ****ptr is main::ptr.

You then increment a pointer to int by 4, thus calculating the address of the fourth int starting from the address of x, and then print that address.

Of course, in the first version *****ptr is main::x, and you then increment int x by 4.

Upvotes: 1

Related Questions