0

Can anyone explain how these values will be printed and why p and *p are returning the same values.

#include <stdio.h>

int main(){
    int arr[] = {1,2,3,4};
    int (*p)[4];

    p = &arr;

    printf("%u %u %u %u %u", arr, &p, p, *p, **p);
    p++;
    printf("\n%u %u %u %u %u", arr, &p, p, *p, **p);

    return 0;
}

outputs on my machine are as follows:

2686768 2686764 2686768 2686768 1

2686768 2686764 2686784 2686784 2686792
Jai Yadav
  • 13
  • 2
  • An object is identified by the pair of its address *and* its type. Different objects can have the same address, provided one is a subobject of another. – Kerrek SB Jun 25 '15 at 10:25
  • arr is the memory address of the starting location of the array. &arr is also the same. p is &arr. *p is arr. – Raman Jun 25 '15 at 10:28
  • Your code is using the wrong `printf()` specifiers, for pointers you should use `"%p"` and cast the parameter to `void`, also you tagged the question c initially, but there is no `using namespace` in c. If you use c++ and included `` then use `std::cout << arr << ", " << p ...` and so on. – Iharob Al Asimi Jun 25 '15 at 10:31
  • You should read http://stackoverflow.com/a/4810668/2651076 to understand how arrays, pointers and pointer to arrays work – Sinstein Jun 25 '15 at 10:40
  • 2
    @iharob: the conversion for `"%p"` must be to `void*` (not `void`) – pmg Jun 25 '15 at 10:58
  • @pmg of course, I meant `void *`. – Iharob Al Asimi Jun 25 '15 at 11:19

2 Answers2

1

Your example is messy, but pointer arithmetic is messy in general, disrespectful to types. Your example does not make sense from a type theory point of view.

arr points to the first element of the array. Note that arr[i] is equivalent to *(arr+i). arr is a 4-elements array of type int.

p is a pointer to a 4-element array of type int.

You assign to p the address of &arr, which has the same address as arr (but the type is different, see below).

Then you print it out and this means:

  • arr is the address of the first element of the array
  • &p is the address of p
  • p is the address of &arr (whole array), which is the address of arr, which is the address of the first element in the array
  • *p is the address of arr, which is the address of the first element in the array
  • **p is trying to dereference *p, which is dereferencing arr, which actually is the first element of the array

After you increment p++: arr and &p don't change, the rest does


From the C Book

We have already emphasized that in most cases, the name of an array is converted into the address of its first element; one notable exception being when it is the operand of sizeof, which is essential if the stuff to do with malloc is to work. Another case is when an array name is the operand of the & address-of operator. Here, it is converted into the address of the whole array. What's the difference? Even if you think that addresses would be in some way ‘the same’, the critical difference is that they have different types. For an array of n elements of type T, then the address of the first element has type ‘pointer to T’; the address of the whole array has type ‘pointer to array of n elements of type T’; clearly very different. Here's an example of it:

int ar[10];
int *ip;
int (*ar10i)[10];       /* pointer to array of 10 ints */

ip = ar;                /* address of first element */
ip = &ar[0];            /* address of first element */
ar10i = &ar;            /* address of whole array */
Lundin
  • 195,001
  • 40
  • 254
  • 396
Ely
  • 10,860
  • 4
  • 43
  • 64
  • Pointer arithmetic is disrespectful to types?! Well then, I disrespect types pretty much everyday :) – P.P Jun 25 '15 at 11:18
  • I mean couldn't you also write p = arr without that the compiler complains? – Ely Jun 25 '15 at 11:29
  • @Elyasin: no, the types won't match. `int (*)[4]` is not compatible with `int *` – John Bode Jun 25 '15 at 12:15
  • Well, I tried that out, and the compiler does not complain. Is it implementation specific? – Ely Jun 25 '15 at 12:29
  • 1
    @Elyasin They are just not compatible. Not sure how you compiled it. Increase the warning level your compiler. You should get a warning for that even without any specific compiler switches though. – P.P Jun 25 '15 at 16:07
  • You're right! I overlooked that somehow. Good to know. – Ely Jun 25 '15 at 21:13
1

printf("%u %u %u %u %u", arr, &p, p, *p, **p);

  • arr is the array itself. When the array name is used in an expression like this, it decays to a pointer to the first element, so you get the address of that element.
  • &p is the address where the array pointer is stored. The only reason why you see this as the same address as the others is because you are running optimized code. Disable optimizations or declare p as static volatile and you'll see a change.
  • p is the address of the array, which will of course be the same as the address of the first element.
  • *p gives you an array type, which then decays into a pointer to the first element. This is identical to arr.
  • **p gives you the contents of the first element in the array.

p++ will increase the pointer by the rules of pointer arithmetic. Thus the address that p points at will be increased by the size of what it points at, which is an array of 4 ints, each 4 bytes large (assuming 32 bit). Therefore p will now point outside valid memory and anything will happen if you try to access it.

Lundin
  • 195,001
  • 40
  • 254
  • 396