tags:

views:

259

answers:

4

In the following bit of code, pointer values and pointer addresses differ as expected.

But array values and addresses don't!

How can this be?

Output

my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC

...

#include <stdio.h>

int main()
{
  char my_array[100] = "some cool string";
  printf("my_array = %p\n", my_array);
  printf("&my_array = %p\n", &my_array);

  char *pointer_to_array = my_array;
  printf("pointer_to_array = %p\n", pointer_to_array);
  printf("&pointer_to_array = %p\n", &pointer_to_array);

  printf("Press ENTER to continue...\n");
  getchar();
  return 0;
}
+5  A: 

That's because the array name (my_array) is different from a pointer to array. It is an alias to the address of an array, and its address is defined as the address of the array itself.

The pointer is a normal C variable on the stack, however. Thus, you can take its address and get a different value from the address it holds inside.

I wrote about this topic here - please take a look.

Eli Bendersky
Precisely correct.
Dan Story
Alexandre
@Alexandre: I'm not sure why it's allowed, actually.
Eli Bendersky
You can take the address of any variable (if not marked `register`) whatever its storage duration: static, dynamic or automatic.
Charles Bailey
`my_array` itself is on the stack, because `my_array` *is* the entire array.
caf
@caf: The array is definitely on the stack, but my_array yields the memory address of the first element. Where is that memory address stored? If it was a pointer (char *) it would be stored on the stack, but in the case of my_array, where is the memory address stored? If the stack has |000|001|002|...|099| , where each is a slot in memory corresponding to the int value of the array's elements, does the compiler reserve another slot to indicate exactly where the first element is in memory?
Alexandre
`my_array`, when not the subject of the ``, it is just like `a + 1`) - conceptually at least it is "calculated as needed". The real "value" of `my_array` is the contents of the entire array - it is just that pinning down this value in C is like trying to catch fog in a jar.
caf
+8  A: 

The name of an array evaluates to the address of the beginning of the array, so array and &array have the same value (but different types, so array+1 and &array+1 will not be equal).

Edit: array evaluates to the address of the first element in the array. For an array defined as T array[size], it will have type T *. When/if you increment it, you get to the next element in the array.

&array evaluates to the same address, but given the same definition, it creates a pointer of the type T (*array)[size] -- i.e. it's a pointer to an array, not to a single element. If you increment this pointer, it'll add the size of the entire array, not the size of a single element. For example, with code like this:

char array[16];
printf("%p\t%p", &array, &array+1);

We can expect the second pointer to be 16 greater than the first (because it's an array of 16 char's). Since %p typically converts pointers in hexadecimal, it might look something like:

0x12341000    0x12341010
Jerry Coffin
Yep, adding 1 to each leads to different results. Do you know what type each belongs to?
Alexandre
Clifford
@Clifford: If you pass array to a function, it decays to a pointer to its first element so effectively ` compilers will warn if the function has a prototype that matches the type of the pointer passed in.
Charles Bailey
@Charles Bailey: Fair enough, if somewhat pedantic since the address of the array and the address of the first element of an array are the same address even if semantically different.
Clifford
@Jerry: PERFECT EXPLANATION!
Alexandre
+3  A: 

In C, when you used the name of an array in an expression (including passing it to a function), unless it is the operand of the address-of (&) operator or the sizeof operator, it decays to a pointer to its first element.

That is, in most contexts array is equivalent to &array[0] in both type and value.

In your example, my_array has type char[100] which decays to a char* when you pass it to printf.

&my_array has type char (*)[100] (pointer to array of 100 char). As it is the operand to &, this is one of the cases that my_array doesn't immediately decay to a pointer to its first element.

The pointer to the array has the same address value as a pointer to the first element of the array as an array object is just a contiguous sequence of its elements, but a pointer to an array has a different type to a pointer to an element of that array. This is important when you do pointer arithmetic on the two types of pointer.

pointer_to_array has type char * - initialized to point at the first element of the array as that is what my_array decays to in the initializer expression - and &pointer_to_array has type char ** (pointer to a pointer to a char).

Of these: my_array (after decay to char*), &my_array and pointer_to_array all point directly at either the array or the first element of the array and so have the same address value.

Charles Bailey