2

I'm currently learning C and I'm confused about memory layout and pointers.

In the following code, it is my understanding that the array is allocated on the stack.

#include <stdio.h> int main () { int x[4]; x[0] = 3; x[1] = 2; x[2] = 1; printf("%p\n",x); printf("%p\n", &x); } 

My question is, why do the two print calls output the same value?

I tried a similar snippet using malloc (allocate on the heap), and the values differ.

#include <stdio.h> #include <stdlib.h> int main () { int *x = malloc(sizeof(int) * 4); x[0] = 3; x[1] = 2; x[2] = 1; printf("%p\n",x); printf("%p\n", &x); } 
19
  • 3
    Possible duplicate of How come an array's address is equal to its value in C? Commented Jan 25, 2017 at 21:02
  • 1
    C does not require using a stack for automatic variables. That's implementation specific. And an array is not a pointer. Commented Jan 25, 2017 at 21:02
  • @Olaf it's implementation specific insofar as all implementations specifically allocate on the stack ;-). Commented Jan 25, 2017 at 21:05
  • 2
    @PeterA.Schneider: There are some embedded CPUs like PIC which don't have a hardware stack. And there are implementations for e.g. HC08 which allow to allocate automatic variables statically for performance reasons for example. An optimised ABI might pass arrays in registers and copy back. An implementation can do quite a lot of things and taking too much for granted is a good way to write code which breaks with good compilers. The world is larger than we think... About taking the address of an array: Try register int a[10];. Commented Jan 25, 2017 at 21:38
  • 1
    @joop Of course: I know, and never said that. The standard actually does not contain the word "stack". But also of course, all implementations known to mankind do provide one. Note that you are entering an ontological discussion about stacks: What is a stack? I'm not saying that a stack has a register ESP, or hardware support of any kind, or a certain memory layout. Perhaps we need a stack Turing test: If it behaves like a stack, it's a stack, however it's implemented? What you describe is just a complicated stack implementation, and thus unlikely to be used instead of a simpler one. Commented Jan 26, 2017 at 11:48

4 Answers 4

3

The reason is that unlike you were probably taught, arrays are not pointers. Arrays in C decay into pointers1 under some circumstances. When you pass an array to a function, it decays into a pointer to the first element. The address of that element is the same as the address of the entire array (an address is always to the first byte of an object).

What you get from malloc is not an array, but the address of a chunk of memory. You assign the address to a pointer. But the pointer and the chunk are separate entities. So printing the value of the pointer, as opposed to its address, yields different results.


(1) Decay is a fancy term for a type of implicit type conversion. When an array expression is used in most places (such as being passed as an argument to a function that expects a pointer), it automatically turns into a pointer to its first element. The "decay" is because you lose type information, i.e. the array size.

Sign up to request clarification or add additional context in comments.

3 Comments

Could you elaborate a bit on what you mean by "decay into pointers"? I've never heard of this behavior before.
Actually the conversion is not related to passing as parameter, but the expression the array is used: port70.net/~nsz/c/c11/n1570.html#6.3.2.1p3
@Olaf - Thanks. Amended to be more in line with the standard.
3

Your two print calls print the same value because one tries to print the array, which decays to a pointer to the array, and the other prints the address of the array. A pointer to the array contains the address of the array, so they're the same value.

In the second case, one prints the value of x, the other prints the address of x. Since x is a pointer to the block of memory you allocated, these must be different values.

So in the first case, all you have is an array (x). In the second case, you have an allocated block of memory (unnamed) and a pointer to that allocated block (x).

3 Comments

Correction: the name of an arra decays to a pointer to the first element (not to the array) for most usages.
I think saying the name decays is misleading. And there's no value distinction between a pointer to an array and a pointer to the first element of the array. Arrays keep all their objects in contiguous memory. But there is a meaning distinction, and here I want the meaning of pointing to the entire array.
Well, the array itself does not decay. Actually, according ot the standard, it is the expression of "array of type" which is converted. And the standard does not disallow using different representations for different types (they need not compare equal). The type is always part of an expression, along with the value. Again you confuse the standard and implementation details. While they are relevant for the question, it is a good idea to point out these differences. Oversimplification and mashing up all together does not really help a beginner.
2

It is perhaps surprising that one can indeed take the address of a whole array, partly because one doesn't need to very often. The array in a sense is a single object, which has one address, which is the address of its first byte. Like with all objects, the address is obtained with the address operator, &.

The first element of an array (like all of its elements) has an address, too, which is the address of its first byte. A pointer to its first element is what the array type is "adjusted" to when it is passed as an argument to a function.

These two bytes are identical, and have the same address. But they have different types, which becomes obvious if you add 1 to them and print them again.

The pointer y, by contrast, is its own distinct object (probably 4 or 8 bytes in size; enough to store an address in it). Like any object it has an address which can be obtained with the & operator. Perhaps confusingly, it also contains an address, in this case the address of the first byte of the array. The two are of course not equal: The pointer object resides at a different location than the array (namely next to it on the stack, even if Olaf doesn't like that).

Minor remark: You use %p for printing pointers, which is good. If you do that, you should strictly spoken cast the pointer which you print to a void pointer: printf("%p\n", (void *)x);.

Comments

0

My question is, why do the two print calls output the same value?

The array is allocated on the stack. The bare symbol without subscript gives the address of the first element. This is an address on the stack. Applying the & (“address of”) operator cannot somehow retrieve a more "fundamental" address – because there isn't any.

The pointer to your other int array allocated on the heap behaves differently. The bare symbol gives the heap address, but by applying the & operator you'll get the stack address of the variable used to hold the pointer. Which is why the two pointer values differ in this case.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.