Abu
Abu

Reputation: 203

How to print pointer to pointers

I am a newbie trying to understand the working of double pointers and to print double pointers. I increment m by one but it's always pointing to the last value pointed by p. Can someone please help me?

#include <stdio.h>

int main () {
   /* an array with 5 elements */
   double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
   double *p;
   double **m;
   int i;

   p = balance;
   m = &p;
   /* output each array element's value */
   printf( "Array values using pointer\n");

   for ( i = 0; i < 5; i++ ) {
     printf("*(p + %d) : %f\n",  i, *(p+i) );
   }

   for ( i = 0; i < 5; i++ ) {
     printf("**(m + %d) : %f\n",  i, *m);
     m++;
   }

   printf( "Array values using balance as address\n");

   for ( i = 0; i < 5; i++ ) {
      printf("*(balance + %d) : %f\n",  i, *(balance + i) );
   }
   return 0;
}

Upvotes: 1

Views: 3336

Answers (2)

John Bode
John Bode

Reputation: 123458

So after you execute

double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
double **m;

p = balance;
m = &p;

the following are all true:

  m == &p                     // double **
 *m ==  p == &balance[0]      // double *
**m == *p ==  balance[0]      // double

(*m)[i] == p[i] == balance[i] // double

Remember that the expression a[i] is defined as *(a + i); given the address a, offset i elements (not bytes1) from that address and dereference the result.

This means that *p is equivalent to *(p + 0), which is equivalent to p[0]. Thus, you can use p[i] in place of balance[i]. Since *m == p, you can also use (*m)[i] in place of p[i]. The parentheses are necessary - unary * has lower precedence than postfix [], so *m[i] would be parsed as *(m[i]), which is not what you want here.

You can increment p directly to "walk" through the balance array:

p = balance; // p == &balance[0];
for ( i = 0; i < 5; i++ )
  printf( "%f\n", *p++ );

Each time through the loop, p is incremented to point to the next element of balance.

You can do something similar with the expression (*m):

p = balance; // p == &balance[0]
m = &p;      

for ( i = 0; i < 5; i++ )
  printf( "%f\n", (*m)++ );

Again, the parentheses around *m are necessary; since postfix ++ has higher precedence than unary *, the expression *m++ would be parsed as *(m++), which is not what we want. We don't want to change the value of m, we want to change the value of what m points to, which in this case is p.

Now, suppose we leave p out of the picture completely; can we do something like:

double balance[5] = { ... };
double **m;

*m = balance;

No. In this example, m is an invalid pointer; it hasn't been initialized to point anywhere meaningful, so *m will invoke undefined behavior (which can include, but is not limited to, a segfault). m has to point to an object of type double * before you can dereference it. There has to be a middleman like p in order for that scheme to work.


  1. Pointer arithmetic always takes the size of the pointed-to type into account - if a points to an object of type T, then a + 1 yields the address of the next object of type T, which may be more than 1 byte away from the current address.

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409136

Your array balance is like this

+--------+--------+--------+--------+--------+
| 1000.0 |    2.0 |    3.4 |   17.0 |   50.0 |
+--------+--------+--------+--------+--------+

After you initialize p and m it is like this:

+---+
| m |
+---+
|
v
+---+
| p |
+---+
|
V
+--------+--------+--------+--------+--------+
| 1000.0 |    2.0 |    3.4 |   17.0 |   50.0 |
+--------+--------+--------+--------+--------+

That is, m points to the location of p, and p points to the first value of the balance array.

When you dereference m (i.e. when you do *m) you get the value of where m is pointing. This value is another pointer (p) that you need to dereference to get to an element in the array.

Using m the second element in balance (i.e. balance[1]) is (*m)[1].


Now if you increment m (with e.g. m++) it will point to the next element of p:

     +---+
     | m |
     +---+
     |
     v
+---+
| p |
+---+
|
V
+--------+--------+--------+--------+--------+
| 1000.0 |    2.0 |    3.4 |   17.0 |   50.0 |
+--------+--------+--------+--------+--------+

You can clearly see the problem here: It no longer points to p and you can no longer us it to access the balance array. Dereferencing m after the increment will lead to undefined behavior.

Also, for any pointer or array, the array-indexing expression and the pointer arithmetic expression are equal. So for balance, the expression balance[i] is equal to *(balance + i). There is really no difference between them.

Upvotes: 1

Related Questions