MEMORY REPRESENTATION IN C
It consists of following segments
- Text segment (i.e. instructions)
- Initialized data segment
- Uninitialized data segment (bss)
- Heap
- Stack
Text segment:
- Read-Only: The text segment is typically marked as read-only to prevent accidental modification of instructions during program execution.
- Stores Code Instructions: It contains the compiled code of the program, including all functions and methods.
- Shared Across Processes: In modern operating systems, the text segment is shared among different processes running the same program, which saves memory by avoiding duplication of the same instructions in memory.
- Fixed Size: The size of the text segment is usually fixed once the program starts.
- +———————+
| Text Segment | <- Stores code and instructions
+———————+
| Data Segment | <- Stores global and static variables
+———————+
| Heap | <- Grows upwards (for dynamic memory allocation)
+———————+
| Stack | <- Grows downwards (for function call frames and local variables)
#include
void greet() {
printf(“Hello, World!\n”); // “Hello, World!\n” is stored in the text segment.
}
int main() {
greet(); // greet() function is stored in the text segment.
return 0;
}
Initialized data segment
- Stores Initialized Variables: This segment holds global and static variables that have been initialized with a non-zero value before the program starts. For example, variables like int count = 10; and char flag = ‘Y’; go into the initialized data segment.
- Allocated at Program Start: Memory for this segment is allocated when the program starts, and variables in this segment retain their values for the lifetime of the program.
- Modifiable at Runtime: Unlike the text segment, which is read-only, the data segment is read-write, allowing these variables to be modified during program execution.
- Fixed Size: The size of the initialized data segment is set when the program loads, based on the static and global variables present and their initial values.
Example of Initialized Data Segment in C
In the following C program, certain global and static variables will be stored in the initialized data segment:
#include <stdio.h>
int count = 10; // Stored in the initialized data segment
static float rate = 3.5; // Stored in the initialized data segment
void display() {
static int calls = 1; // Stored in the initialized data segment, persists across function calls
printf(“Function call number: %d\n”, calls);
calls++;
}
int main() {
display(); // First call
display(); // Second call
return 0;
}
Uninitialized data segment (bss):
Stores Uninitialized Variables: The BSS segment holds global and static variables that have been declared but not initialized. For example, variables like int count; or float rate; without an explicit initial value go into the BSS segment.
Automatically Zero-Initialized: Variables in the BSS segment are automatically set to zero (or NULL for pointers) when the program starts, even though they aren’t explicitly initialized by the programmer.
Read-Write: The BSS segment is modifiable during the program’s execution, so variables stored here can be read and updated.
Fixed Size on Program Load: The size of the BSS segment is determined at program load time based on the total memory requirements for all uninitialized global and static variables.
Example of the BSS Segment in C
Consider the following C code:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr = (int *)malloc(5 * sizeof(int)); // Allocate memory for an array of 5 integers
if (arr == NULL) {
printf(“Memory allocation failed\n”);
return 1;
}
// Assign values and use the allocated memory
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
printf(“%d “, arr[i]);
}
free(arr); // Free the allocated memory
return 0;
}
Characteristics of the Heap
- Dynamic Allocation: The heap allows memory to be allocated and deallocated at runtime using functions like malloc(), calloc(), realloc() (for allocation), and free() (for deallocation) in C.
- Grows Upward: The heap typically grows upward in memory, opposite to the stack, which grows downward.
- Global Accessibility: Memory allocated on the heap persists throughout the program’s life unless explicitly freed. It can be accessed from any function in the program, making it ideal for data that needs to persist between function calls.
- Requires Manual Management: Because the programmer controls memory allocation and deallocation, failing to free memory (memory leaks) or freeing memory incorrectly can lead to issues like memory leaks, undefined behavior, or segmentation faults.
- Relatively Slower Access: Accessing heap memory is generally slower than accessing stack memory due to the overhead of dynamic memory management.
Example of Heap Allocation in C
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr = (int *)malloc(5 * sizeof(int)); // Allocate memory for an array of 5 integers
if (arr == NULL) {
printf(“Memory allocation failed\n”);
return 1;
}
// Assign values and use the allocated memory
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
printf(“%d “, arr[i]);
}
free(arr); // Free the allocated memory
return 0;
}
In this example, malloc allocates memory on the heap for an array of 5 integers. This memory remains allocated until we explicitly release it with free().
Stack
- Automatic Allocation and Deallocation: Memory for local variables and function parameters is automatically allocated on the stack when a function is called and freed when the function exits.
- Grows Downward: The stack generally grows downward in memory, opposite to the heap.
- Limited Size: The stack has a fixed, limited size determined by the system. Exceeding the stack size (such as with excessive recursion or large local arrays) can cause a stack overflow.
- Fast Access: Accessing stack memory is fast due to its contiguous nature and managed order, making it well-suited for local variables and function calls.
- Automatic Management: The system automatically manages stack memory, so programmers don’t need to manually allocate or free memory for local variables.
Example of Stack Allocation in C
#include <stdio.h>
void display() {
int num = 10; // Local variable, allocated on the stack
printf(“Number: %d\n”, num);
}
int main() {
display();
return 0;
}
In this example, num is a local variable created on the stack when display() is called. When display() completes, num is automatically deallocated.