Reputation: 349
Question from code below:
#include <stdio.h>
int main(int argc,char *arg[]){
if (argc>2){
int m=atoi(arg[1]);
int n=atoi(arg[2]);
int a[m][n];
int (*p)[m][n]=&a;
printf("p : %p, *p : %p, **p : %p\n",p,*p,**p);
}
return 0;
}
Main Env: gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) x86-64
gcc main.c
./a.out 2 4
output:
p : 0xbfea7ef0, *p : 0xbfea7ef0, **p : 0xbfea7ef0
Question is why p == *p == **p
. I think this may be because a
is an array, kind of constant pointer which address is something specific, and this involves some implementation detail of gcc.
Upvotes: 4
Views: 129
Reputation: 753845
The observed behaviour is the same for fixed-size arrays and variably-modified arrays:
#include <stdio.h>
int main(void)
{
enum { m = 3, n = 4 };
int a[m][n];
int (*p)[m][n] = &a;
printf("p : %p, *p : %p, **p : %p\n", p, *p, **p);
return(0);
}
On my machine, this produced:
p : 0x7fff6c542520, *p : 0x7fff6c542520, **p : 0x7fff6c542520
Of course, p
is a pointer to a 2D array in both programs (and I shan't add the 'in both programs' qualifier again, even though it applies). When you print p
, you get the address of the array that's assigned to it, which is the address of a
. Because p
is a pointer to a 2D array, *p
'is' the 2D array, but an array reference becomes a pointer to its first element in most situations, so *p
is a pointer to a[0]
, which is the same memory location as a
references. Similarly, **p
'is' a 1D array, but similarly, **p
is a pointer to a[0][0]
, which is also the same memory location as a
references. So, the three values are supposed to be the same, and the compiler gets it right.
That's not easy reading, but then, neither is the C that it is trying to explain.
Here's a minor variation on the original program which illustrates the sizes of the different objects pointed at by p
, *p
and **p
:
#include <stdio.h>
int main(void)
{
enum { m = 3, n = 4 };
int a[m][n];
int (*p)[m][n]=&a;
printf("p+0 : %p, (*p)+0 : %p, (**p) + 0 : %p\n",
(void *)(p+0), (void *)((*p)+0), (void *)((**p)+0));
printf("p+1 : %p, (*p)+1 : %p, (**p) + 1 : %p\n",
(void *)(p+1), (void *)((*p)+1), (void *)((**p)+1));
return(0);
}
Strictly, the %p
conversion specification should be given a void *
; the casts here enforce that. The original code is, officially, a bit sloppy, though there are few machines where it would matter.
The output from this was:
p+0 : 0x7fff63453520, (*p)+0 : 0x7fff63453520, (**p) + 0 : 0x7fff63453520
p+1 : 0x7fff63453550, (*p)+1 : 0x7fff63453530, (**p) + 1 : 0x7fff63453524
Note how the sizes of the objects pointed at are different, as represented by the +1
version:
sizeof(*p) = 0x30
sizeof(**p) = 0x10
sizeof(***p) = 0x04
Upvotes: 1
Reputation: 179422
p
is a pointer to an array with dimensions [m][n]
. The value of that pointer is the address of a
, so printing p
gets you the address of a
.
*p
is an array with dimensions [m][n]
. The "value" of this as a pointer is a pointer to the first element of the array, which is a[0]
. This is the same address as a
.
**p
is an array with dimensions [n]
. The value of this pointer is a pointer to the first element of the array, which is a[0][0]
. This is the same address as a
again.
Upvotes: 7