233

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;
}
phant0m
  • 16,595
  • 5
  • 50
  • 82
Alexandre
  • 5,035
  • 7
  • 29
  • 36
  • 3
    I had added an answer with diagram to this question two years back here [What does `sizeof(&array)` return?](http://stackoverflow.com/a/15177499/1673391) – Grijesh Chauhan May 08 '15 at 16:39
  • 1
    From the comp.lang.c FAQ: - [So what is meant by the ``equivalence of pointers and arrays'' in C? ](http://c-faq.com/aryptr/aryptrequiv.html) - [Since array references decay into pointers, if arr is an array, what's the difference between arr and &arr? ](http://c-faq.com/aryptr/aryvsadr.html) Or go read the entire [Arrays and Pointers](http://c-faq.com/aryptr/index.html) section. – jamesdlin Mar 27 '10 at 09:18
  • Does this answer your question? [What is array to pointer decay?](https://stackoverflow.com/questions/1461432/what-is-array-to-pointer-decay) – Andreas Wenzel Jan 11 '22 at 06:46

6 Answers6

251

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
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Yep, adding 1 to each leads to different results. Do you know what type each belongs to? – Alexandre Mar 27 '10 at 06:33
  • 3
    @Alexandre: `&array` is a pointer to the first element of the array, where as `array` refers to the entire array. The fundamental difference can also be observed by comparing `sizeof(array)`, to `sizeof(&array)`. Note however that if you pass `array` as an argument to a function, only `&array` is in fact passed. You cannot pass an array by value unless it is encapsulated withing a `struct`. – Clifford Mar 27 '10 at 07:52
  • 19
    @Clifford: If you pass array to a function, it decays to a pointer to its first element so effectively `&array[0]` is passed, not `&array` which would be a pointer to the array. It may be a nit-pick but I think it's important to make clear; compilers will warn if the function has a prototype that matches the type of the pointer passed in. – CB Bailey Mar 27 '10 at 09:53
  • 1
    @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 Mar 27 '10 at 20:48
  • 2
    @Jerry Coffin For example int *p = &a, if I want the memory address of the int pointer p, I can do &p. Since &array converts to the address of the whole array (which starts at the address of the first element). Then how do I find the memory address of the array pointer (which stores the address of the first element in the array)? It must be somewhere in the memory right? – John Lee Sep 12 '12 at 08:44
  • 2
    @JohnLee: No, there does not have to be a pointer to the array anywhere in memory. If you create a pointer, you can then take its address: `int *p = array; int **pp = &p;`. – Jerry Coffin Sep 12 '12 at 14:06
  • @JerryCoffin Thanks. I read in a C book. It says "When you create a pointer variable, the machine will allocate 4 or 8 bytes of space to store it. But what if you create an array? The computer will allocate space to store the array, but it won’t allocate any memory to store the array variable. The compiler simply plugs in the address of the start of the array." – John Lee Sep 12 '12 at 15:56
  • @JohnLee: That quotation doesn't make much sense. Do you know what "it won't allocate any memory to store the array *variable*" means? Perhaps the word "variable" is being used in some odd way. – Keith Thompson Sep 14 '12 at 22:11
  • I think this answer fails to explain *why* only in the context of static allocated arrays does `variable == &variable` – Dan F May 10 '13 at 18:44
  • @DanF: There's no such thing to explain -- given a local array, `variable` and `&variabl`e will give the same address. – Jerry Coffin May 10 '13 at 19:31
  • @JerryCoffin FYI, There are two more cases when an array doesn't decay into a pointer: when it's the operand of C11's `alignof` operator, and when it's a string literal (`char []`) which is used to initialize a char array. (Also, in C++, another exception is, AFAIK, when an array is passed by reference, but we are not talking about C++ here anyway.) –  Aug 06 '13 at 13:41
  • 1
    Why &(array+1) results in error "lvalue required as unary '&' operand". array+1 is not a literal. So confused with this behavior. – Rajesh Mar 04 '17 at 15:45
  • 3
    @Clifford the first comment is wrong, why still keep it? I think it might lead to misunderstanding for those who don't read the following (@Charles) reply. – Rick Apr 09 '18 at 02:24
  • The name of an array usually evaluates to the address of the first element of the array, AND so array and &array have the same value - These two parts are not related – Алексей Неудачин Jul 21 '20 at 19:25
38

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
  • 263,248
  • 89
  • 350
  • 412
  • Shouldn't &my_array be an invalid operation since my_array's value isn't on the stack, only my_array[0...length] are? Then it would all make sense... – Alexandre Mar 27 '10 at 06:22
  • @Alexandre: I'm not sure why it's allowed, actually. – Eli Bendersky Mar 27 '10 at 06:46
  • You can take the address of any variable (if not marked `register`) whatever its storage duration: static, dynamic or automatic. – CB Bailey Mar 27 '10 at 10:00
  • `my_array` itself is on the stack, because `my_array` *is* the entire array. – caf Mar 27 '10 at 12:42
  • @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 Mar 28 '10 at 05:02
  • 3
    `my_array`, when not the subject of the `&` or `sizeof` operators, is evaluated to a pointer to its first element (ie. `&my_array[0]`) - but `my_array` itself is **not** that pointer (`my_array` is still the array). That pointer is just an ephemeral rvalue (eg. given `int a;`, 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 Mar 28 '10 at 21:18
  • `my_array` is the name of an array. It's not "an alias to the address of an array". Since `my_array` designates an array, it's tautological to say that `&my_array` is defined as the address of the array. This is just the same as how with `int x;` , `&x` is defined as the address of the int. The array is a stack variable (in this case - of course, you can make them static and so on), so you can take its address in just the same way that you can take an `int`'s address. – M.M Jul 28 '14 at 23:02
  • Thx for the detailed blog-post. You missed one thing though: I can imagine a perfectly fine use for pointers to array. It is to encode in the type-system the size of array. I'd say it's mostly for human readers, but there's more to it: if you try passing a pointer to an array of different size, the compiler gonna warn you like `expected ‘int (*)[5]’ but argument is of type ‘int (*)[4]’` – Hi-Angel Jun 24 '17 at 18:44
31

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
5

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].
R Sahu
  • 204,454
  • 14
  • 159
  • 270
4

In the B programming language, which was the immediate predecessor to C, pointers and integers were freely interchangeable. The system would behave as though all of memory was a giant array. Each variable name had either a global or stack-relative address associated with it, for each variable name the only things the compiler had to keep track of was whether it was a global or local variable, and its address relative to the first global or local variable.

Given a global declaration like i; [there was no need to specify a type, since everything was an integer/pointer] would be processed by the compiler as: address_of_i = next_global++; memory[address_of_i] = 0; and a statement like i++ would be processed as: memory[address_of_i] = memory[address_of_i]+1;.

A declaration like arr[10]; would be processed as address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;. Note that as soon as that declaration was processed, the compiler could immediately forget about arr being an array. A statement like arr[i]=6; would be processed as memory[memory[address_of_a] + memory[address_of_i]] = 6;. The compiler wouldn't care whether arr represented an array and i an integer, or vice versa. Indeed, it wouldn't care if they were both arrays or both integers; it would perfectly happily generate the code as described, without regard for whether the resulting behavior would likely be useful.

One of the goals of the C programming language was to be largely compatible with B. In B, the name of an array [called a "vector" in the terminology of B] identified a variable holding a pointer which was initially assigned to point to to the first element of an allocation of the given size, so if that name appeared in the argument list for a function, the function would receive a pointer to the vector. Even though C added "real" array types, whose name was rigidly associated with the address of the allocation rather than a pointer variable that would initially point to the allocation, having arrays decompose to pointers made code which declared a C-type array behave identically to B code which declared a vector and then never modified the variable holding its address.

supercat
  • 77,689
  • 9
  • 166
  • 211
1

Actually &myarray and myarray both are the base address.

If you want to see the difference instead of using

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

use

printf("my_array = %s\n", my_array);
printf("my_array = %p\n", my_array);
glglgl
  • 89,107
  • 13
  • 149
  • 217
Ravi Bisla
  • 405
  • 1
  • 4
  • 10