C Memory Management with Examples – 5 Layers

C memory management divides the memory into several sections, where each serving a unique purpose.  when a program runs, the operating system loads machine code into different memory sections in a structured way. This 5-layer structured memory layout helps the OS manage resources effectively, balancing memory usage and access speed, which are key for program execution.

Memory management in C programming

You Must Know !!

Compiler: The compiler translates source code into machine code (or an executable file) and defines memory layout in terms of program sections (like the code, data, and stack sections). However, it does not actually assign or allocate memory at runtime. The compiler includes instructions for memory allocation but doesn’t perform it directly.· 

Loader (Part of OS): The loader is a program that takes the compiled machine code and loads it into the computer’s main memory segments (like the stack, heap, data, and text segments), and prepares it for execution.

The sections of main memory layout is given below

  1. Code (Text) Segment
  2. Data Segment
    • Initialized Data Segment
    • Uninitialized Data Segment (BSS)
  3. Heap Segment
  4. Stack Segment
  5. Command Line Arguments and Environment Variables Segment

Following is a simple descriptive memory layout diagram for memory management in C

Let’s explain each section, their purpose, what data resides there, and how they are managed in a simple way.

1. Code (Text) Segment:

The Code Segment (or Text Segment) contains the instructions that tell the computer what to do.

For Examples: when you call printf() to print something, the computer doesn’t “know” how to print by itself. Instructions for printf() are stored in the Code Segment from the standard library to handle this task. These instructions were compiled from C code to machine code by compiler and are stored in the Code Segment by OS. The CPU fetches instructions from this segment during execution.

The machine code for printf() (built-in function) and sayHello() (user-defined function) is also stored in the Code Segment because these are instructions that tell the computer to perform accordingly.

Key Points:

  • Read-Only: The code segment is typically read-only, which means that the instructions cannot be modified during runtime. This helps protect the program from accidental or malicious changes to its instructions.
  • Fixed Size: The size of the code segment is determined at compile-time and doesn’t change during the execution of the program.

2. Data Segment (Const. / Static / Global)

The Data Segment in C stores global variables and static variables, which retain their values throughout the program’s execution. It also contains constant data which cannot be modified during execution.

In the statement printf(“hello %d”, 5); The string  “hello %d” is considered a constant value and is stored in the Data Segment because it does not change during the execution of the program. The integer value 5 is typically stored on the Stack when passed as an argument to the printf function.

This segment is divided into two parts:

a) Initialized Data Segment: Global, static and constant variables that are explicitly initialized by the programmer. Allocated and initialized before main()

Example:

int globalVar = 100;  // global initialized variable
static int staticVar = 200;  // static initialized variable
const float pi = 3.14; // Const refers to values that do not change during the execution of a program

b) Uninitialized Data Segment (BSS): Global, static, and const. variables that are declared but not initialized. They are automatically set to zero.

Example:

int uninitializedGlobalVar;  // global uninitialized variable
static int uninitializedStaticVar;  // static uninitialized variable
const float pi;

3. Heap Section

Dynamically allocated memory (using malloc, calloc, realloc, free). Managed manually by the programmer during runtime.

Example:

int *ptr = (int*) malloc(sizeof(int));  // dynamically allocated memory on the heap
*ptr = 10;

Grows: Heap grows towards higher memory addresses as memory is dynamically allocated.

4. Stack Section

Local variables and function call information’s (like return addresses, function parameters, etc.). Automatically managed by the system when a function is called.

void myFunction() {
    int localVar = 50;  // local variable stored on the stack
}

Keep in mind, myFunction() itself stored in code segment

  • LIFO: Stack grows towards lower memory addresses and operates in a Last In, First Out (LIFO) manner.
  • Scope-limited: Memory is freed when a function returns.

5. Command Line Arguments and Environment Variables

When a program runs In C, environment variables and command-line arguments are reside in a special section at the top of the memory layout, separate from the stack.

It is separate at the top because environment variables and command-line arguments need to be consistently accessible and not affected by the dynamic changes in the stack, which grows and shrinks with each function call.

  • Environment variables provide information about the system, such as the location of system files or configuration settings. These variables are passed from the OS and stored in memory for the program to use.
#include <stdio.h>
int main(int argc, char *argv[], char *envp[]) {
    printf("First environment variable: %s\n", envp[0]);
    printf("Second environment variable: %s\n", envp[1]);
    return 0;
}

Output:

First environment variable: ALLUSERSPROFILE=C:\ProgramData

Second environment variable: APPDATA=C:\Users\EURO TEC COMPUTERS\AppData\Roaming

Note: Here, the environment variables can be accessed via the envp[] array. Command-line arguments Allow users to pass input to the program at runtime.

#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("Program name: %s\n", argv[0]);
    if (argc > 1) {
        printf("First argument: %s\n", argv[1]);
    }
    return 0;
}

Output

Program name: C:\Users\EURO TEC COMPUTERS\Desktop\C Programig Practice\C Programming\bin\Debug\C Programming.exe

Note: Here, the Command line arguments can be accessed via the argv[] array.

Environment Variables Vs. Command-Line Arguments

Feature Environment Variables Command-Line Arguments
Purpose Provide system-level information and settings. Allow users to pass input to the program at runtime.
Scope Typically available to all processes spawned by the OS. Specific to the program run and passed during execution.
Access Method in C Accessed using getenv() or envp[]. Accessed via argc and argv[].
Example Use Provide information like file paths, configuration dirs. Pass a filename, number, or option to a program.
Persistence Exist outside of the program and can affect many programs. Exist only during the execution of a specific program.