How come an array's address is equal to its value in C?
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;
}
The name of an array usually evaluates to the address of the first element of the array, so array
and &array
have the same value (but different types, so array+1
and &array+1
will not be equal if the array is more than 1 element long).
There are two exceptions to this: when the array name is an operand of sizeof
or unary &
(address-of), the name refers to the array object itself. Thus sizeof array
gives you the size in bytes of the entire array, not the size of a pointer.
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(*)[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", (void*)&array, (void*)(&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
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.
In C, when you use 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.
The reason why my_array
and &my_array
result in the same address can be easily understood when you look at the memory layout of an array.
Let's say you have an array of 10 characters (instead the 100 in your code).
char my_array[10];
Memory for my_array
looks something like:
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array.
In C/C++, an array decays to the pointer to the first element in an expression such as
printf("my_array = %p\n", my_array);
If you examine where the first element of the array lies you will see that its address is the same as the address of the array:
my_array[0]
|
v
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array[0].