Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointer to pointer clarification

Tags:

c

pointers

People also ask

How do you define pointer to pointer?

A pointer to a pointer is a form of multiple indirection, or a chain of pointers. Normally, a pointer contains the address of a variable. When we define a pointer to a pointer, the first pointer contains the address of the second pointer, which points to the location that contains the actual value as shown below.

Can a pointer point to another pointer in C?

Introduction. Note that the pointer ptr is itself a variable and hence, it will be allocated some memory on the memory stack. Thus, it will have a memory address of its own. A pointer to a pointer in C or a double pointer will point to this memory address of the pointer.

What is pointer write down declaration of pointer with example?

The declarator names the variable and can include a type modifier. For example, if declarator represents an array, the type of the pointer is modified to be a pointer to an array. You can declare a pointer to a structure, union, or enumeration type before you define the structure, union, or enumeration type.

What only works when a pointer has a Pointee?

The dereference operation on a pointer only works if the pointer has a pointee -- the pointee must be allocated and the pointer must be set to point to it. The most common error in pointer code is forgetting to set up the pointee.


Forget for a second about the pointing analogy. What a pointer really contains is a memory address. The & is the "address of" operator - i.e. it returns the address in memory of an object. The * operator gives you the object a pointer refers to, i.e. given a pointer containing an address, it returns the object at that memory address. So when you do *ipp = ip2, what you are doing is *ipp get the object at the address held in ipp which is ip1 and then assign to ip1 the value stored in ip2, which is the address of j.

Simply
& --> Address of
* --> Value at


Because you changed the value pointed to by ipp not the value of ipp. So, ipp still points to ip1 (the value of ipp), ip1's value is now the same as ip2's value, so they both point to j.

This:

*ipp = ip2;

is the same as:

ip1 = ip2;

Like most beginner questions in the C tag, this question can be answered by going back to first principles:

  • A pointer is a kind of value.
  • A variable contains a value.
  • The & operator turns a variable into a pointer.
  • The * operator turns a pointer into a variable.

(Technically I should say "lvalue" instead of "variable", but I feel it is more clear to describe mutable storage locations as "variables".)

So we have variables:

int i = 5, j = 6;
int *ip1 = &i, *ip2 = &j;

Variable ip1 contains a pointer. The & operator turns i into a pointer and that pointer value is assigned to ip1. So ip1 contains a pointer to i.

Variable ip2 contains a pointer. The & operator turns j into a pointer and that pointer is assigned to ip2. So ip2 contains a pointer to j.

int **ipp = &ip1;

Variable ipp contains a pointer. The & operator turns variable ip1 into a pointer and that pointer value is assigned to ipp. So ipp contains a pointer to ip1.

Let's sum up the story so far:

  • i contains 5
  • j contains 6
  • ip1 contains "pointer to i"
  • ip2 contains "pointer to j"
  • ipp contains "pointer to ip1"

Now we say

*ipp = ip2;

The * operator turns a pointer back into a variable. We fetch the value of ipp, which is "pointer to ip1 and turn it into a variable. What variable? ip1 of course!

Therefore this is simply another way of saying

ip1 = ip2;

So we fetch the value of ip2. What is it? "pointer to j". We assign that pointer value to ip1, so ip1 is now "pointer to j"

We only changed one thing: the value of ip1:

  • i contains 5
  • j contains 6
  • ip1 contains "pointer to j"
  • ip2 contains "pointer to j"
  • ipp contains "pointer to ip1"

Why does ipp still point to ip1 and not ip2?

A variable changes when you assign to it. Count the assignments; there cannot be more changes to variables than there are assignments! You start by assigning to i, j, ip1, ip2 and ipp. You then assign to *ipp, which as we've seen means the same as "assign to ip1". Since you didn't assign to ipp a second time, it didn't change!

If you wanted to change ipp then you'll have to actually assign to ipp:

ipp = &ip2;

for instance.


hope this piece of code can help.

#include <iostream>
#include <stdio.h>
using namespace std;

int main()
{
    int i = 5, j = 6, k = 7;
    int *ip1 = &i, *ip2 = &j;
    int** ipp = &ip1;
    printf("address of value i: %p\n", &i);
    printf("address of value j: %p\n", &j);
    printf("value ip1: %p\n", ip1);
    printf("value ip2: %p\n", ip2);
    printf("value ipp: %p\n", ipp);
    printf("address value of ipp: %p\n", *ipp);
    printf("value of address value of ipp: %d\n", **ipp);
    *ipp = ip2;
    printf("value ipp: %p\n", ipp);
    printf("address value of ipp: %p\n", *ipp);
    printf("value of address value of ipp: %d\n", **ipp);
}

it outputs:

enter image description here


My very personal opinion is that pictures with arrows pointing this way or that make pointers harder to understand. It does make them seem like some abstract, mysterious entities. They are not.

Like everything else in your computer, pointers are numbers. The name "pointer" is just a fancy way of saying "a variable containing an address".

Therefore, let me stir things around by explaining how a computer actually works.

We have an int, it has the name i and the value 5. This is stored in memory. Like everything stored in memory, it needs an address, or we wouldn't be able to find it. Lets say i ends up at address 0x12345678 and its buddy j with value 6 ends up just after it. Assuming a 32-bit CPU where int is 4 bytes and pointers are 4 bytes, then the variables are stored in physical memory like this:

Address     Data           Meaning
0x12345678  00 00 00 05    // The variable i
0x1234567C  00 00 00 06    // The variable j

Now we want to point at these variables. We create one pointer to int, int* ip1, and one int* ip2. Like everything in the computer, these pointer variables get allocated somewhere in memory too. Lets assume they end up at the next adjacent addresses in memory, immediately after j. We set the pointers to contain the addresses of the variables previously allocated: ip1=&i; ("copy the address of i into ip1") and ip2=&j. What happens between the lines is:

Address     Data           Meaning
0x12345680  12 34 56 78    // The variable ip1(equal to address of i)
0x12345684  12 34 56 7C    // The variable ip2(equal to address of j)

So what we got were just yet some 4 byte chunks of memory containing numbers. There's no mystical or magical arrows anywhere in sight.

In fact, just by looking at a memory dump, we can't tell whether the address 0x12345680 contains an int or int*. The difference is how our program chooses to use the contents stored at this address. (The task of our program is actually just to tell the CPU what to do with these numbers.)

Then we add yet another level of indirection with int** ipp = &ip1;. Again, we just get a chunk of memory:

Address     Data           Meaning
0x12345688  12 34 56 80    // The variable ipp

The pattern does seem familiar. Yet another chunk of 4 bytes containing a number.

Now, if we had a memory dump of the above fictional little RAM, we could manually check where these pointers point. We peek at what's stored at the address of the ipp variable and find the contents 0x12345680. Which is of course the address where ip1 is stored. We can go to that address, check the contents there, and find the address of i, and then finally we can go to that address and find the number 5.

So if we take the contents of ipp, *ipp, we will get the address of the pointer variable ip1. By writing *ipp=ip2 we copy ip2 into ip1, it is equivalent to ip1=ip2. In either case we would get

Address     Data           Meaning
0x12345680  12 34 56 7C    // The variable ip1
0x12345684  12 34 56 7C    // The variable ip2

(These examples were given for a big endian CPU)


Notice the assignments:

ipp = &ip1;

results ipp to point to ip1.

so for ipp to point to ip2, we should change in the similar manner,

ipp = &ip2;

which we are clearly not doing. Instead we are changing the value at address pointed by ipp.
By doing the folowing

*ipp = ip2;

we are just replacing the value stored in ip1.

ipp = &ip1 , means *ipp = ip1 = &i,
Now, *ipp = ip2 = &j.
So, *ipp = ip2 is essentially same as ip1 = ip2.


ipp = &ip1;

No later assignment has changed the value of ipp. This is why it still points to ip1.

What you do with *ipp, i.e., with ip1, does not change the fact that ipp points to ip1.