1Learning Outcomes¶
Learn characteristics of the C memory layout.
Differentiate between storage allocation and variable declaration.
Know where variables are stored in C, i.e., which memory segment data is allocated in.
🎥 Lecture Video
[CS61C FA20] Lecture 05.3 - C Memory Management: Memory Locations"
until 8:37
2C Memory Layout¶
So far, we have discussed how different data types occupy space (i.e., how the compile-time operator sizeof works with different declarations of local variables), but we haven’t discussed where all C things live in memory.
2.1Memory allocation¶
In C, there are three ways of allocating storage space in memory:
Local variable declaration: To specify a local variable, declare it inside a function, e.g., in
main(). Local variables are accessible within the function they are declared in; put another way, a C compiler will only recognize a local variable in its function’s namespace. These are declared and allocated at compile-time (hence whysizeofworks).Global variable declaration: Global variables are declared outside a function. Variables declared in the global namespace are accessible to every subroutine (
main(),foo(), etc.). Warning: Do not overuse global variables! While they are useful for accessing shared constants or big tables, you can write the worst code in the world by having a billion globals: you risk accidental edits by different routines, and you remove the power of abstraction between functions. Global variables are declared and allocated at compile-time.Dynamic memory allocation: Sometimes we won’t know how much space we need until we start running a program. For example, we may need to load in data from a file, and we only know how much data is in the file until we read all of its bytes. In this case, we can dynamically allocate memory storage at runtime by calling allocation functions:
mallocis a common one. Read more when we discuss heaps.
Based on the descriptions above, note that storage allocation involves setting aside a block of memory to put data in. Variable declaration means allocating a block of memory and also specifying a name with which to refer to that memory. Because variables are typed, variable declaration implicitly specifies the size of the memory block to allocate. While variable declaration always implies storage allocation, the converse is not true (e.g., with dynamic memory allocation).
2.2Four regions of memory layout¶
A C program’s address space contains 4 regions as shown in Figure 1.

Figure 1:C program memory layout.
| Memory Segment | Contents | Memory Management |
|---|---|---|
| Stack | local variables, parameters, and return addresses [1] | automatic; grows downward[2] |
| Heap | dynamically allocated storage | resizes on demand (e.g. malloc to allocate storage, free to free storage); grows upward[3] |
| Data (aka Static) | global variables | size is fixed (“static”) throughout the whole program |
| Text (aka Code) | program code | size is fixed throughout the whole program; data is loaded when program starts |
The names of these four memory segments are hard to memorize at first, so we apologize on behalf of all computer scientists. While the stack operates very much like the stack data structure you learned in a Data Structures course, the heap is NOT a heap data structure; it is just a “heap of memory.” Also, everything is technically data, but the data segment specifically refers to global data. Finally, the text can be remembered because program code should be read-only data, just like how many texts you read in real life are read-only.
Programming in C requires knowing where data is in memory[4]. Otherwise things don’t work as expected. In particular, memory in each of the four regions is managed differently. The biggest source of bugs in C is from incorrect assumptions about memory. This lecture is all about learning how memory is managed in order to avoid common bugs. We focus our discussion on the stack and the heap.
Because parameters and return addresses are critical to function call and return, they are often stored directly in the CPU where possible—on special hardware called registers (which we talk about later). Because there are only a limited number of such registers, additional parameters and return addresses are stored in memory on the stack until they are needed.
By contrast, Java and Python both hide locations of objects.