Does stack grow upward or downward?

user188276 picture user188276 · Nov 5, 2009 · Viewed 72.5k times · Source

I have this piece of code in c:

int q = 10;
int s = 5;
int a[3];

printf("Address of a: %d\n",    (int)a);
printf("Address of a[1]: %d\n", (int)&a[1]);
printf("Address of a[2]: %d\n", (int)&a[2]);
printf("Address of q: %d\n",    (int)&q);
printf("Address of s: %d\n",    (int)&s);

The output is:

Address of a: 2293584
Address of a[1]: 2293588
Address of a[2]: 2293592
Address of q: 2293612
Address of s: 2293608

So, I see that from a to a[2], memory addresses increases by 4 bytes each. But from q to s, memory addresses decrease by 4 byte.

I wonder 2 things:

  1. Does stack grow up or down? (It looks like both to me in this case)
  2. What happen between a[2] and q memory addresses? Why there are a big memory difference there? (20 bytes).

Note: This is not homework question. I am curious on how stack works. Thanks for any help.

Answer

Ganesh Gopalasubramanian picture Ganesh Gopalasubramanian · Nov 7, 2009

The behavior of stack (growing up or growing down) depends on the application binary interface (ABI) and how the call stack (aka activation record) is organized.

Throughout its lifetime a program is bound to communicate with other programs like OS. ABI determines how a program can communicate with another program.

The stack for different architectures can grow the either way, but for an architecture it will be consistent. Please check this wiki link. But, the stack's growth is decided by the ABI of that architecture.

For example, if you take the MIPS ABI, the call stack is defined as below.

Let us consider that function 'fn1' calls 'fn2'. Now the stack frame as seen by 'fn2' is as follows:

direction of     |                                 |
  growth of      +---------------------------------+ 
   stack         | Parameters passed by fn1(caller)|
from higher addr.|                                 |
to lower addr.   | Direction of growth is opposite |
      |          |   to direction of stack growth  |
      |          +---------------------------------+ <-- SP on entry to fn2
      |          | Return address from fn2(callee) | 
      V          +---------------------------------+ 
                 | Callee saved registers being    | 
                 |   used in the callee function   | 
                 +---------------------------------+
                 | Local variables of fn2          |
                 |(Direction of growth of frame is |
                 | same as direction of growth of  |
                 |            stack)               |
                 +---------------------------------+ 
                 | Arguments to functions called   |
                 | by fn2                          |
                 +---------------------------------+ <- Current SP after stack 
                                                        frame is allocated

Now you can see the stack grows downward. So, if the variables are allocated to the local frame of the function, the variable's addresses actually grows downward. The compiler can decide on the order of variables for memory allocation. (In your case it can be either 'q' or 's' that is first allocated stack memory. But, generally the compiler does stack memory allocation as per the order of the declaration of the variables).

But in case of the arrays, the allocation has only single pointer and the memory needs to be allocated will be actually pointed by a single pointer. The memory needs to be contiguous for an array. So, though stack grows downward, for arrays the stack grows up.