Reputation: 690
I write such code
int a = 0;
int b = 0;
int *m = (int *)malloc(2* sizeof(int));
printf("%x, %x\n", &a, &b);
printf("%x, %x", &m[0], &m[1]);
and get result:
46372e18, 46372e1c
d062ec20, d062ec24
Is not that that stack grow down and heap up?
Upvotes: 1
Views: 299
Reputation: 40594
Yes, the stack grows down on virtually all modern systems. However, 1. that is an implementation detail, and 2. that is in terms of stack frames, not individual variables.
When your function gets called, it creates a stack frame on the stack, which is basically a region of stack memory that is used to hold the local variables. Where each function is placed within this stack frame, is entirely up to the compiler.
However, if you ran this code:
void foo() {
int b;
printf("%p\n", (void*)&b);
}
int main() {
int a;
printf("%p\n", (void*)&a);
foo();
}
you would see that the address of b
is smaller than the address of a
: When foo()
gets called, it creates a new stack frame, and b
will be inside this stack frame, which will be below the stack frame allocated by main()
.
For the heap, there is no notion of direction whatsoever. Of course, most allocators will exhibit some patterns in how they allocate their memory, but as they all reuse memory that was free()
'd, they all break their patterns at some point.
Upvotes: 0
Reputation: 2547
As pointed out by many , C stranded doesn't specify anything about this.
However I want to touch on the different aspect , test you are doing is not sufficient to determine the heap is growing up-words or down-words.
Update the code as shown below and check the results;
#include <stdio.h>
#include <stdlib.h>
void test()
{
int a = 0;
int b = 0;
printf("4:%p, %p\n", (void *)&a,(void *)&b);
}
void main() {
int a = 0;
int b = 0;
int *m = malloc(2* sizeof(int));
int *n = malloc(2* sizeof(int));
printf("1:%p, %p\n",(void *)&a,(void *)&b);
printf("2:%p, %p\n",(void *)&m[0],(void *)&m[1]);
printf("3:%p, %p\n",(void *)&n[0],(void *)&n[1]);
test();
}
On my System I can see that heap address "increasing" and stack address "decreasing"
In your code you dont have any function call so stack frame is only one.
Upvotes: 0
Reputation: 140148
because of pointer arithmetic:
printf("%x, %x", &m[0], &m[1]);
(note that printing pointer values requires %p
format, other formats can "work" but they can break too)
address of m[1]
is address of m[0]
plus sizeof(int)
, that doesn't depend on where m
is allocated (global or auto)
and here:
int a = 0;
int b = 0;
As opposed to structure members, the compiler may locate auto variables wherever it chooses relatively to each other. It may swap them, group the ones with lower alignment constraint, etc... So you're looking at an implementation detail here.
Upvotes: 1
Reputation: 140445
To learn which way "the"1 "stack"2 grows, you must make at least one function call. Something like this, for instance:
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
static ptrdiff_t
stack_probe(uintptr_t stack_addr_from_main)
{
int var;
uintptr_t stack_addr_from_me = (uintptr_t)&var;
return ((intptr_t) stack_addr_from_me) -
((intptr_t) stack_addr_from_main);
}
int
main(void)
{
int var;
uintptr_t stack_addr_from_main = (uintptr_t)&var;
ptrdiff_t stack_delta = stack_probe(stack_addr_from_main);
printf("Stack offset from one function call = %td\n", stack_delta);
return 0;
}
You must do it this way because most compilers allocate all of the stack space for a function call all at once, upon entry, in what's called a "stack frame", and organize the space within as they see fit. Therefore, comparing the address of two variables local to the same function doesn't tell you anything useful. You must also take care to compile this program with "inlining" turned off; if the compiler is allowed to merge stack_probe
into main
, then it will all be one stack frame again and the results will be meaningless. (Some compilers let you control inlining on a function-by-function basis, but there's no standard way to do that as far as I know.)
The number printed by this program is "unspecified" by the C standard3 (that means "it will print some number, but the standard doesn't require it to be any particular number"). However, on almost all computers you are likely to be able to get your hands on today, it will print a negative number, and that means the stack grows downward. If you manage to run it on a PA-RISC machine running HP-UX (it might not even compile, unfortunately; I don't remember if HP-UX ever had a C99-conformant library) it will print a positive number, and that means the stack grows upward.
There have been computers on which the number printed by this program wouldn't mean anything, because their equivalent of a "stack" was not necessarily a contiguous block of memory. Look up "split stacks" for the simplest version of that.
The "heap," incidentally, does not necessarily grow up or down. Consecutive calls to malloc
return pointers with no meaningful relationship to each other, always.
1 There can be more than one stack, for instance when threads are in use.
2 Fun fact: the word "stack" appears nowhere in the C standard. There is a requirement to support recursive function calls, but how the implementation manages that is left completely up to the implementation.
3 Also, it is implementation-defined whether this program will compile, because the implementation is not required to provide intptr_t
and uintptr_t
. But if I hadn't used those types, the program would have undefined behavior ("it's allowed to do anything at all, including crashing and having all of its code deleted") because you're only allowed to take the difference of two pointers when they point into the same array, which these don't.
Upvotes: 8
Reputation: 44256
All of this is not specified by the standard. The standard doesn't even mention stack and heap. Both of these are implementation details that isn't required by the standard.
Further you only have one dynamic object (malloc'ed object) and it will follow the normal layout for an array. So from that you can't say anything about how the heap grows on your system. If you want to try to see what your system does, you'll need at least two malloc'ed objects.
To print pointers use:
printf("%p, %p\n", (void*)&a, (void*)&b);
Upvotes: 3