In C programming, understanding the memory layout of variables is essential for efficient memory management. A program’s memory is divided into several segments: text, data, BSS, heap, and stack. These segments help organize code, variables, and dynamically allocated memory.
1. Text Segment
The text segment, also called the code segment, holds the compiled instructions of the program. This is a read-only area to prevent accidental modification of instructions during execution. For example:
int main() {
printf("Hello, World!\n"); // This resides in the text segment
}
2. Data Segment
The data segment is used to store initialized global and static variables. It is further divided into two sections:
- Read-Only Data: Stores constant variables.
- Read-Write Data: Stores initialized variables that can be modified during program execution.
int global_var = 10; // Initialized global variable stored in the data segment
static int static_var = 5; // Initialized static variable also stored in the data segment
3. BSS Segment
The BSS (Block Started by Symbol) segment contains uninitialized global and static variables. These variables are initialized to zero by default during runtime. The BSS segment helps reduce the size of the executable, as it does not physically store the data but just reserves the space.
int uninitialized_global_var; // Stored in the BSS segment
static int uninitialized_static_var; // Also stored in the BSS segment
4. Heap Segment
The heap segment is used for dynamic memory allocation. Memory is allocated and freed manually using functions like malloc()
, calloc()
, and free()
. Heap memory remains in use until explicitly deallocated, making it suitable for variables whose lifetime needs to persist beyond a single function.
int *dynamic_var = (int*) malloc(sizeof(int)); // Stored in the heap segment
5. Stack Segment
The stack segment manages function calls and local variables. Whenever a function is called, a stack frame is created to hold its local variables, return address, and parameters. The stack grows and shrinks as functions are called and returned, following a Last-In-First-Out (LIFO) approach.
void function() {
int local_var = 10; // Stored in the stack segment
}
Example of Memory Layout in a C Program:
Consider the following C program to understand how different variables are allocated across these segments:
#include <stdio.h>
#include <stdlib.h>
int global_var = 10; // Data segment
static int static_var; // BSS segment
int main() {
int local_var = 20; // Stack segment
int *dynamic_var = (int*) malloc(sizeof(int)); // Heap segment
*dynamic_var = 30;
printf("Global: %d, Static: %d, Local: %d, Dynamic: %d\n", global_var, static_var, local_var, *dynamic_var);
free(dynamic_var);
return 0;
}
Following is the program which details the simple memory layout of the c program. As we can see in this, program memory is divided into the text, various data, and stack and heap sections.
$ vim address_space.c
#include <stdio.h>
int bss_var; /* Uninitialized global variable */
int data_var = 1; /* Initialized global variable */
int main(int argc, char **argv) {
void *stack_var;
/* Local variable on the stack */
stack_var = (void *)main;
/* Don't let the compiler */
/* optimize it out */
printf("Hello, World! Main is executing at %p\n", &stack_var);
printf("This address (%p) is in our stack frame\n", &stack_var);
/* bss section contains uninitialized data */
printf("This address (%p) is in our bss section\n", &bss_var);
/* data section contains initializated data */
printf("This address (%p) is in our data section\n", &data_var);
return 0;
}
$ gcc -o address_space address_space.c
$ ./address_space
Hello, World! Main is executing at 0x804846b
This address (0xbffccbb8) is in our stack frame
This address (0x804a028) is in our bss section
This address (0x804a020) is in our data section
Refer https://en.wikipedia.org/wiki/Data_segment for more details.