Memory layout of a C program typically represented by five main segments:
- Stack Segment: Local variables reside in stack, and it also handles function call management.
- Heap Segment: All dynamic memory allocation (memory allocation during runtime using functions like malloc(), calloc(), …etc.) manages by heap dynamic.
- BSS (Uninitialized Data Segment): Stores global and static variables that are initialized to zero by default.
- DS (Initialized Data Segment): Stores global and static variables that are explicitly initialized and retain their values throughout program execution.
- Text Segment: Contains the compiled code instructions.
Each segment of C code has its own read, write, and executable permission. These permissions are set by the operating system and the compiler. 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).
But before explaining the memory layout of C code, I also want to let you know that the actual memory layout in C might be more complex, as it depends on the processor, development tools, and underlying hardware.
The below diagram shows a visual representation of how RAM loads a program written in C into several segments.
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 ----> '----------------------'
So, let’s get understand the generalized typical memory organization of C program without wasting the much time.
Stack:
- The stack memory segment is a contiguous block of memory. It primarily consists of stack frames, stack pointer (SP), and the frame pointer (FP) or base pointer (BP)
- When a function is called, a block is reserved on the top of the stack for local variables, function parameters, and some bookkeeping data (activation record). But when that function returns, the reserved block becomes unused and can be used the next time a function is called.
- 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 used for dynamic memory allocation and deallocation in a program.
- In C language, the heap segment 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 (b​lock 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.
Examples:
Let see few examples to understand the memory layout of the C program. In the below examples I will use the size command to check the sizes (in bytes) of these different memory segments. The size command basically lists section sizes as well as total size for the input object file.
#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
Let us 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 (uninitialized data segment) it increased by 4 bytes by adding one uninitialized static integer variable.
Let us add one 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
You can see the size of the .ds (initialized data segment) it increased by 4 bytes by adding one initialized static integer variable.
Let us add one uninitialized global 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 (uninitialized data segment) it increased by 4 bytes by adding one uninitialized global integer variable.
Let us add one uninitialized global and one static 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
You can see the size of the .bss (uninitialized data segment) it increased by 8 bytes by adding one uninitialized global and static integer variable.
Let us add one initialized global and one static 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
You can see the size of the .ds (initialized data segment) it increased by 8 bytes by adding one initialized global and static integer variable.
Also, in the data segment, I have said that the “data segment can be further classified into the two-parts:
- Read-only area.
- Read-write area.
Let us see C programs to understand this classification and 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; }
You will get the compiler error here. A string literal cannot modify and goes to the read only section (normally the .rodata segment) and also similar to the string literal generally const global data also goes in .rodata segment.
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.