The memory layout of C program mainly comprises five segments these are the stack segment, heap segment, BSS (block started by symbol), DS (Data Segment), and text segment. But you should remember actual memory layout in C might be more complex because C program memory layout is specific to the processor, development tools, and the underlying hardware.
Before explaining the memory layout of C code, I also want to let you know that each segment of memory layout in C has its own read, write, and executable permission. If a program tries to access the memory in a way that is not allowed, then a segmentation fault occurs.
A segmentation fault is a common problem that causes programs to crash. A core file (core dumped file) is also associated with a segmentation fault that is used by the developer to find the root cause of the crash (segmentation fault).
So, let’s get understand the generalized typical memory organization in a C program without wasting the much time.
Typical memory Layout of C Program:
Note: You must remember that this is only an example. The actual static memory layout is specific to the processor, development tools, and the underlying hardware.
1. Stack
2. Heap
3. BSS (Uninitialized data segment)
4. DS (Initialized data segment)
5. Text
High Addresses ---> .----------------------. | Environment | |----------------------| | | Functions and variable are declared | STACK | on the stack. base pointer -> | - - - - - - - - - - -| | | | | v | : : . . The stack grows down into unused space . Empty . while the heap grows up. . . . . (other memory maps do occur here, such . . as dynamic libraries, and different memory : : allocate) | ^ | | | | brk point -> | - - - - - - - - - - -| Dynamic memory is declared on the heap | HEAP | | | |----------------------| | BSS | Uninitialized data (BSS) |----------------------| | Data | Initialized data (DS) |----------------------| | Text | Binary code Low Addresses ----> '----------------------'
Stack:
- The stack memory segment is used to store local variables, function parameters, and bookkeeping information related to function call. When a function is called, a block is reserved on the top of the stack for local variables and some bookkeeping data.
- Stack memory segment follow the LIFO (Last-In-First-Out) structure, that means the last item pushed onto the stack is the first one to be removed. It also depends on the computer architecture that stack grows down to the lower address or not; Also, when functions are called and return, their corresponding stack frames are pushed and popped from the stack.
- Stack grows in the direction opposite to heap.
- A stack frame is created in the stack when a function is called and destroyed when the function returns. It also known as an activation record or activation frame. Stack frame holds information about a function’s execution and its temporary and local variables. Let’s consider an example for better understanding,
void aticleworld(int x, int y, int z) { int C; // Some operations }
In the above example, when function aticleworld() is called, a stack frame for aticleworld() is created. Within this stack frame, memory is allocated for the function parameters x, y, z and for the local variable C. This stack frame also stored the return address to the calling function and any necessary register values that need to be preserved across the function calls.
- Each function call in a program creates its own stack frame that allows different instances of the same function (called separately or recursively) do not interfere with each other’s variables or execution contexts. For better understanding consider the below example code,
int fact(int a) { if (a <= 1) { return 1; } else { //recursive call of function return (a* fact(a- 1)); } }
In the above example, each recursive call to function fact() creates its own stack frame. And each call to function has its own set of parameters and local variables. That means in each calling of fact() has its own local variable “a” that does not interfere with the “a” of other instances of the function fact(). It ensures the isolation between another instance of fact().
- SP (Stack pointer) register keeps track of the top of the stack. The SP helps manage the stack efficiently by pointing to the current top of the stack. Its value change when push/pop actions are performed on the segment.
Heap:
- Heap memory segment is used to allocate the memory at run time. That means it allows dynamic memory allocation and deallocation during runtime.
- The heap area is managed by the memory management functions like malloc, calloc, free, etc which may internally use the brk() and sbrk() system calls to adjust its size.
- The Heap area is shared by all shared libraries and dynamically loaded modules in a process.
- You must manage the heap memory carefully to prevent memory leaks and another issue related to dynamic memory allocation.
- It grows and shrinks in the opposite direction of the stack.
#include <stdio.h> int main(void) { char *pStr = malloc(sizeof(char)*4); //stored in heap return 0; }
You can also see below articles,
- Dynamic memory allocation in C
- Common mistakes with memory allocation
- Questions about dynamic memory allocation
Uninitialized data segment:
- An uninitialized data segment is also known as BSS (block started by symbol).
- Uninitialized data segment contains all uninitialized global and static variables.
- All variables in this segment initialized by the zero (0) and pointer with the null pointer.
- The program loader allocates memory for the BSS section when it loads the program.
#include <stdio.h> int data1; // Uninitialized global variable stored in BSS int main(void) { static int data2; // Uninitialized static variable stored in BSS return 0; }
Initialized data segment:
- The initialized data segment, also known as the data segment; it contains the explicitly initialized global and static variables.
- Initialized data segment is distinct from the BSS (Block Started by Symbol) segment.
- The size of this segment is determined by the size of the values in the program’s source code and does not change at run time.
- Typically, initialized data segment has read-write permission so the value of the variable of this segment can be changed at run time.
- This segment can be further classified into an initialized read-only area and an initialized read-write area.
#include <stdio.h> int data1 = 10 ; //Initialized global variable stored in DS int main(void) { static int data2 = 3; //Initialized static variable stored in DS return 0; }
Text:
- The text segment contains a binary of the compiled program.
- The text segment is a read-only segment that prevents a program from being accidentally modified.
- It is sharable so that only a single copy needs to be in memory for frequently executed programs such as text editors etc.
Note: The size command basically lists section sizes as well as total size for the input object file.
Let see few examples to understand the memory layout of the C program.
#include <stdio.h> int main(void) { return 0; }
[aticleworld@CentOS]$ gcc memory-layout.c -o memory-layout [aticleworld@CentOS]$ size memory-layout text data bss dec hex filename 960 248 8 1216 4c0 memory-layout
- Now add a static uninitialized variable and check the size.
#include <stdio.h> int main(void) { static int data; // Stored in uninitialized area return 0; }
[aticleworld@CentOS]$ gcc memory-layout.c -o memory-layout [aticleworld@CentOS]$ size memory-layout text data bss dec hex filename 960 248 12 1216 4c0 memory-layout
You can see the size of the .bss has been increased.
- Now add the initialized static variable and check the size.
#include <stdio.h> int main(void) { static int data =10; // Stored in initialized area return 0; }
[aticleworld@CentOS]$ gcc memory-layout.c -o memory-layout [aticleworld@CentOS]$ size memory-layout text data bss dec hex filename 960 252 8 1216 4c0 memory-layout
See the size of the data segment has been increased.
- Now add the global uninitialized variable and check the size.
#include <stdio.h> int data; // Stored in uninitialized area int main(void) { return 0; }
[aticleworld@CentOS]$ gcc memory-layout.c -o memory-layout [aticleworld@CentOS]$ size memory-layout text data bss dec hex filename 960 248 12 1216 4c0 memory-layout
You can see the size of the .bss has been increased.
- Now add the global and static uninitialized variable and check the size.
#include <stdio.h> int data1; //Stored in uninitialized area int main(void) { static int data2; //Stored in uninitialized area return 0; }
[aticleworld@CentOS]$ gcc memory-layout.c -o memory-layout [aticleworld@CentOS]$ size memory-layout text data bss dec hex filename 960 248 16 1216 4c0 memory-layout
The size of .bss increases as per the uninitialized global and static variables.
- Now add the global and static initialized variable and check the size.
#include <stdio.h> int data1 = 0; //Stored in uninitialized area int main(void) { static int data2 = 0; //Stored in uninitialized area return 0; }
[aticleworld@CentOS]$ gcc memory-layout.c -o memory-layout [aticleworld@CentOS]$ size memory-layout text data bss dec hex filename 960 264 8 1216 4c0 memory-layout
The size of the data segment increases as per the initialized global and static variables.
In the data segment, I have said that the “data segment can be further classified into the two-part initialized read-only area and an initialized read-write area”. So let us see two C programs to understand this concept.
#include <stdio.h> char str[]= "Amlendra Kumar"; int main(void) { printf("%s\n",str); str[0]='k'; printf("%s\n",str); return 0; }
Output:
Amlendra Kumar kmlendra Kumar
You can see the above example str is a global array, so it will go in the data segment. You can also see that I am able to change the value so it has read and write permission.
Now see the other example code,
#include <stdio.h> char *str= "Amlendra Kumar"; int main(void) { str[0]='k'; printf("%s\n",str); return 0; }
In the above example, we are not able to change the array character because it is a literal string. A constant string does not only go in the data section but all types of const global data go in that section.
It is not necessarily that const global and constant strings go in the data section. It can be also in the text section of the program (normally the .rodata segment), as it is normally not modifiable by a program.
MCQ On Memory layout in C Programs:
Recommended Posts for you
- Internal, external and none linkage in C.
- What is recursion in C.
- Create a students management system in C.
- Create an employee management system in C.
- Top 11 Structure Padding Interview Questions in C
- structure in C: you should know in depth
- What is flexible array member in c?
- What is importance of struct hack in c?
- How to use the structure of function pointer in c language?
- Function pointer in structure.
- Pointer Arithmetic in C.
- Union in C, A detailed Guide.
- typedef vs #define in C.
- Macro in C, with example code.
- enum in C, you should know.
- You should know the volatile Qualifier.
- 100 C interview Questions.
- Interview questions on bitwise operators in C.
- A brief description of the pointer in C.
- Dangling, Void, Null and Wild Pointers
- 10 questions about dynamic memory allocation.
- File handling in C.
- Pointer in C.
- C language character set.
- Elements of C Language.
- Data type in C language.
- Operators with Precedence and Associativity in C.
- C format specifiers.
- C++ Interview Questions.
Thank You for this awesome article
Thanks, Anbu and Welcome for the suggestion.
You are excellent 👍
Thanks, Afreen.
Thanks for giving simple explanation. I couldn’t pick up some points in class. Now that doubts are clear.
Thank you so much..
Nice and informative
Thanks and welcome for suggestion.
Thank you somuch…
Thank you so much really i have learnt so much from Article.com
Bro, I have a doubt
How does text area increase.
Thanks in advance.
Text area depends on the binary size (code size). If the size of binary increases text area also increases. You can check the memory map (.map) file for better understanding.