Open In App

Memory Layout of C Programs

Last Updated : 18 Oct, 2025
Comments
Improve
Suggest changes
643 Likes
Like
Report

The memory layout of a program shows how its data is stored in memory during execution. It helps developers understand and manage memory efficiently.

  • Memory is divided into sections such as code, data, heap, and stack.
  • Knowing the memory layout is useful for optimizing performance, debugging and prevent errors like segmentation fault and memory leak.
Memory-Layout-of-C-Program

1. Text Segment

  • The text segment (or code segment) stores the executable code of the program like program’s functions and instructions.
  • The segment is usually read-only to prevent accidental modification during execution.
  • It is typically stored in the lower part of memory.
  • The size of the text segment depends on the number of instructions and the program’s complexity.

2. Data Segment

  • The data segment stores global and static variables of the program.
  • Variables in this segment retain their values throughout program execution.
  • The size of the data segment depends on the number and type of global/static variables.
  • It is divided into initialized and uninitialized (BSS) sections.

A. Initialized Data Segment

As the name suggests, it is the part of the data segment that contains global and static variables that have been initialized by the programmer.

C
#include <stdio.h>

// Global variables (stored in initialized data segment)
int globalVar = 10;
char message[] = "Hello";

int main()
{
    // Static variable (also stored in initialized data segment)
    static int staticVar = 20;

    printf("Global variable: %d\n", globalVar);
    printf("Static variable: %d\n", staticVar);
    printf("Message: %s\n", message);

    return 0;
}

The above variables a and b will be stored in the Initialized Data Segment.

B. Uninitialized Data Segment (BSS)

  • The uninitialized data segment is often called the BSS segment.
  • It stores global and static variables that are not initialized by the programmer.
  • These variables are automatically initialized to zero by the system at runtime.
C
#include <stdio.h>

// Global uninitialized variables (stored in BSS segment)
int globalVar;
char message[50];

int main()
{
    // Static uninitialized variable (also stored in BSS)
    static int staticVar;

    // Assigning values at runtime
    globalVar = 10;
    staticVar = 20;
    snprintf(message, sizeof(message), "Hello BSS");

    printf("Global variable: %d\n", globalVar);
    printf("Static variable: %d\n", staticVar);
    printf("Message: %s\n", message);

    return 0;
}

Output
Global variable: 10
Static variable: 20
Message: Hello BSS

3. Heap Segment

  • The heap segment is used for dynamic memory allocation.
  • It starts at the end of the BSS segment and grows towards higher memory addresses.
  • Memory in the heap is managed using functions like malloc(), realloc(), and free().
  • The heap is shared by all shared libraries and dynamically loaded modules in a process.
C
#include <stdio.h>
#include <stdlib.h>

int main() {
    
    // Create an integer pointer
    int *ptr = (int*) malloc(sizeof(int) * 10); 
    return 0;
}

Output

4. Stack Segment

  • The stack stores local variables, function parameters, and return addresses for each function call.
  • Each function call creates a stack frame in this segment.
  • The stack is usually at higher memory addresses and grows opposite to the heap.
  • When the stack and heap meet, the program’s free memory is exhausted.
C
#include <stdio.h>

void func() {
    
    // Stored in the stack
    int local_var = 10;  
}

int main() {
    func();
    return 0;
}

Output

Practical Examples

The size(1) command in MinGW reports the sizes (in bytes) of the text, data, and bss segments of a binary file.

1. Check the following simple C program 

C
#include <stdio.h>

int main() {
    return 0;
}

Output
gcc memory-layout.c -o memory-layout
size memory-layout
text data bss dec hex filename
960 248 8 1216 4c0 memory-layout

2. Let us add one global variable in the program, now check the size of bss

C
#include <stdio.h>

// Uninitialized variable stored in bss
int global;
int main() {
    return 0;
}

Output
gcc memory-layout.c -o memory-layout
size memory-layout
text data bss dec hex filename
960 248 12 1220 4c4 memory-layout

3. Let us add one static variable which is also stored in bss.

C
#include <stdio.h>

// Uninitialized variable stored in bss
int global;
int main() {
  
  	// Uninitialized static variable stored in bss
    static int i;
    return 0;
}

Output
gcc memory-layout.c -o memory-layout
size memory-layout
text data bss dec hex filename
960 248 16 1224 4c8 memory-layout

4. Let us initialize the static variable which will then be stored in the Data Segment (DS)

C
#include <stdio.h>

// Uninitialized variable stored in bss
int global;
int main(void) {
  	
  	// Initialized static variable stored in DS
    static int i = 100;
    return 0;
}

Output
gcc memory-layout.c -o memory-layout
size memory-layout
text data bss dec hex filename
960 252 12 1224 4c8 memory-layout

5. Let us initialize the global variable which will then be stored in the Data Segment (DS)

C
#include <stdio.h>

// initialized global variable stored in DS
int global = 10;
int main() {
  
  	// Initialized static variable stored in DS
    static int i = 100;
    return 0;
}

Output
gcc memory-layout.c -o memory-layout
size memory-layout
text data bss dec hex filename
960 256 8 1224 4c8 memory-layout

Example to Verify the Memory Layout

C
#include <stdio.h>
#include <stdlib.h>

// Global variable
int gvar = 66;

// Constant global variable
const int cgvar = 1010;

// uninitialized global variable
int ugvar;

void foo() {
    
    // Local variable
    int lvar = 1;
    printf("Address of lvar:\t%p", (void*)&lvar);
}

int main() {
    
    // Heap variable
    int *hvar = (int*)malloc(sizeof(int));
    
    
    // Checking and comparing address of different
    // elements of program that should be stored in
    // different segements of the memory
    printf("Address of foo:\t\t%p\n", (void*)&foo);
    printf("Address of cgvar:\t%p\n", (void*)&cgvar);
    printf("Address of gvar:\t%p\n", (void*)&gvar);
    printf("Address of ugvar:\t%p\n", (void*)&ugvar);
    printf("Address of hvar:\t%p\n", (void*)hvar);
    foo();
    
	return 0;
}

Output
Address of foo:		0x400670
Address of cgvar:	0x4007a4
Address of gvar:	0x600b40
Address of ugvar:	0x600b48
Address of hvar:	0xce86010
Address of lvar:	0x7ffea42e2f3c


Output

Address of foo:         0x60d723996189
Address of cgvar: 0x60d723997004
Address of gvar: 0x60d723999010
Address of ugvar: 0x60d723999018
Address of hvar: 0x60d73b9072a0
Address of lvar: 0x7ffd0e85e0c4

Comparing above addresses, we can see than it roughly matches the memory layout discussed above.


Memory Structure of a Program
Visit Course explore course icon

Explore