Very basically, in C programs built to target ELF (Executable and Linkable Format) such as those built on linux there is a standard memory layout that is created. Similar layouts probably exist for other architectures, but I don't know enough to tell you more about them.
The Layout:
There are some global data sections that are initialized at low memory addresses in memory (such as sections for the currently executing code, global data, and any strings that are created with "..."
inside your C code).
Below that there is a heap of open memory that can be used. The size of this heap increases automatically as calls to malloc and free move what is called the "program break" to higher addresses in memory.
Starting at a high address in memory, the stack grows towards lower addresses. The stack contains memory for any locally allocated variables, such as those at the top of functions or within a scope ({ ... }
).
More Info:
There is a good description of a running ELF program here and more details on the format itself on the Wikipedia article. If you want an example of how a compiler goes about translating C code into assembly you might look at GCC, their Internals Manual has some interesting stuff in it; the most relevant sections are probably those in chapter 17, especially 17.10, 17.19 and 17.21. Finally, Intel has a lot of information about memory layout in its IA-32 Architectures Software Developer’s Manual. It describes how Intel processors handle memory segmentation and the creation of stacks and the like. There's no detail about ELF, but it's possible to see where the two match up. The most useful bits are probably section 3.3 of Volume 1: Basic Architecture, and chapter 3 of Volume 3A: System Programming Guide, Part 1.
I hope this helps anyone diving into the internals of running C programs, good luck.