Mamrot
Mamrot

Reputation: 349

address of pointer to C multi-dimension array

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

Answers (2)

Jonathan Leffler
Jonathan Leffler

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

nneonneo
nneonneo

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

Related Questions