The reason this occurred is that all normal compilers store objects with automatic storage duration (objects declared inside a block that are not static
or extern
) on a stack. Your compiler “pushed” a
onto the stack, which means it wrote a
to the memory location where the stack pointer was pointing and then decremented the pointer. (Decrementing the pointer adds to the stack, because the stack grows in the direction of decreasing memory addresses. Stacks can be oriented in the other direction, but the behavior you observed strongly suggests your system uses the common direction of growing downward.) Then your compiler pushed b
onto the stack. So b
ended up at a memory address just below a
.
When you took the address of b
and added one, that produced the memory address where a
is. When you used that address to assign 5, that value was written to where a
is.
None of this behavior is defined by the C standard. It is a consequence of the particular compiler you used and the switches you compiled with.
You probably compiled with little or no optimization. With optimization turned on, many compilers would simplify the code by removing unnecessary steps (essentially replacing them with shortcuts), so that 20 and 10 are not actually stored on the stack. A possible result with optimization is that “20” and “10” are printed, and your assignment to *x
has no effect. However, the C standard does not say what the behavior must be when you use *x
in this way, so the results are determined only by the particular compiler you are using, along with the input switches you give it.