Reputation: 203
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
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.
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
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