1.15 Memory Management in C Programming
Module 1.15 • Architectural Segments, Static & Dynamic Allocation, Manual Heap Release
1.15.1 Introduction
Memory management is one of the most important concepts in C programming. Unlike many modern programming languages, C does not automatically manage memory. The programmer must allocate memory when needed and release it when it is no longer required.
Efficient memory management helps programs:
- Run faster
- Use memory efficiently
- Avoid crashes
- Prevent memory leaks
- Handle large amounts of data dynamically
Understanding memory management is essential for developing reliable and efficient applications.
1.15.2 Memory Organization in C
When a C program executes, memory is divided into different sections.
+----------------------+
| Code Segment |
+----------------------+
| Data Segment |
+----------------------+
| Heap |
+----------------------+
| Stack |
+----------------------+
Each section serves a different purpose.
1.15.3 Stack Memory
Stack memory is automatically managed by the compiler.
Characteristics
- Stores local variables
- Stores function parameters
- Stores return addresses
- Fast access
- Limited size
- Automatically released
Example
#include<stdio.h>
int main()
{
int marks = 85;
printf("%d", marks);
return 0;
}
Here, marks is stored in stack memory.
Lifetime of Stack Variables
Memory is allocated when a function starts and automatically released when the function ends.
Example:
void demo()
{
int num = 40;
}
When demo() finishes execution, memory occupied by num is released automatically.
1.15.4 Heap Memory
Heap memory is used for dynamic memory allocation.
Characteristics
- Allocated during runtime
- Managed by programmer
- Large memory area
- Flexible size
- Must be manually released
Example applications:
- Dynamic arrays
- Linked lists
- Trees
- Graphs
- Database records
1.15.5 Data Segment
Stores:
- Global variables
- Static variables
Example:
int total = 100;
static int count = 5;
These variables remain available throughout program execution.
1.15.6 Code Segment
Contains executable machine instructions of the program.
Example:
printf("Hello");
The compiled instructions are stored in the code segment.
1.15.7 Static Memory Allocation
Memory size is determined before program execution.
Example:
int numbers[10];
Memory is reserved during compilation.
Advantages
- Simple
- Fast access
Limitations
- Fixed size
- Memory may be wasted
Example Program
#include<stdio.h>
int main()
{
int scores[4] = {55, 68, 72, 90};
for(int i=0;i<4;i++)
{
printf("%d ", scores[i]);
}
return 0;
}
Output:
55 68 72 90
1.15.8 Dynamic Memory Allocation
Dynamic memory allocation allows memory to be allocated during runtime.
Benefits:
- Flexible size
- Efficient memory usage
- Suitable for large applications
C provides four important functions:
malloc()
calloc()
realloc()
free()
All are available in:
#include <stdlib.h>
1.15.9 malloc()
malloc stands for Memory Allocation. It allocates a block of memory and returns a pointer to the first byte.
Syntax
ptr = (datatype*) malloc(size);
Example: Allocate Memory for 6 Integers
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *ptr;
ptr = (int*)malloc(6 * sizeof(int));
if(ptr == NULL)
{
printf("Allocation Failed");
return 1;
}
for(int i=0;i<6;i++)
{
ptr[i] = (i + 1) * 15;
}
for(int i=0;i<6;i++)
{
printf("%d ", ptr[i]);
}
free(ptr);
return 0;
}
Output:
15 30 45 60 75 90
Important Note
Memory allocated by malloc contains garbage values initially.
Example:
int *ptr;
ptr = (int*)malloc(4 * sizeof(int));
Contents are undefined until assigned.
1.15.10 calloc()
calloc stands for Contiguous Allocation. It allocates memory and initializes all bytes to zero.
Syntax
ptr = (datatype*)calloc(number_of_elements, size_of_each_element);
Example Program
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *ptr;
ptr = (int*)calloc(5,sizeof(int));
if(ptr == NULL)
{
printf("Allocation Failed");
return 1;
}
for(int i=0;i<5;i++)
{
printf("%d ", ptr[i]);
}
free(ptr);
return 0;
}
Output:
0 0 0 0 0
1.15.11 malloc vs calloc
| Feature | malloc() | calloc() |
|---|---|---|
| Initialization | Garbage Values | Zero Initialized |
| Arguments | One | Two |
| Speed | Slightly Faster | Slightly Slower |
| Usage | General Allocation | Arrays |
1.15.12 realloc()
realloc changes the size of previously allocated memory.
Syntax
ptr = realloc(ptr,new_size);
Used when data grows or shrinks dynamically.
Example Program
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *ptr;
ptr = (int*)malloc(3 * sizeof(int));
if(ptr == NULL)
{
return 1;
}
ptr[0] = 10;
ptr[1] = 20;
ptr[2] = 30;
ptr = realloc(ptr,6 * sizeof(int));
if(ptr == NULL)
{
return 1;
}
ptr[3] = 40;
ptr[4] = 50;
ptr[5] = 60;
for(int i=0;i<6;i++)
{
printf("%d ",ptr[i]);
}
free(ptr);
return 0;
}
Output:
10 20 30 40 50 60
Why realloc is Useful
Suppose a user enters unknown amounts of data. Instead of allocating huge memory initially:
int *data = malloc(1000*sizeof(int));
You can start small:
int *data = malloc(10*sizeof(int));
and expand later using: realloc(). This improves memory efficiency.
1.15.14 free()
free releases dynamically allocated memory.
Syntax
free(ptr);
After freeing memory: ptr = NULL; is recommended.
Example Program
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *ptr;
ptr = (int*)malloc(4*sizeof(int));
free(ptr);
ptr = NULL;
return 0;
}
Why Set Pointer to NULL?
After free: free(ptr);, the pointer still contains an old address. This creates a dangling pointer.
Safe practice:
free(ptr);
ptr = NULL;
1.15.16 Dynamic Array Example
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n;
printf("Enter size: ");
scanf("%d",&n);
int *arr;
arr = (int*)malloc(n*sizeof(int));
if(arr == NULL)
{
printf("Allocation Failed");
return 1;
}
for(int i=0;i<n;i++)
{
arr[i] = (i+1)*5;
}
printf("Array Elements:\n");
for(int i=0;i<n;i++)
{
printf("%d ",arr[i]);
}
free(arr);
return 0;
}
Sample Output:
Enter size: 5
Array Elements:
5 10 15 20 25
1.15.17 Dynamic Memory for Structures
Memory can also be allocated for structures.
struct Employee
{
int id;
float salary;
};
Allocation:
struct Employee *emp;
emp = (struct Employee*) malloc(sizeof(struct Employee));
Example Program
#include<stdio.h>
#include<stdlib.h>
struct Employee
{
int id;
float salary;
};
int main()
{
struct Employee *emp;
emp = malloc(sizeof(struct Employee));
emp->id = 101;
emp->salary = 45000.50;
printf("%d\n",emp->id);
printf("%.2f\n",emp->salary);
free(emp);
return 0;
}
Output:
101
45000.50
1.15.18 Common Memory Errors
Improper memory handling can create serious bugs.
Memory Leak
Memory is allocated but never released.
Bad Example:
int *ptr;
ptr = malloc(sizeof(int));
return 0;
Memory remains occupied.
Correct:
free(ptr);
Dangling Pointer
Pointer references memory already released.
Bad Example:
free(ptr);
printf("%d",*ptr);
Undefined behavior.
Double Free
Freeing same memory twice.
Bad Example:
free(ptr);
free(ptr);
May crash the program.
Buffer Overflow
Writing beyond allocated memory.
Example:
int *ptr;
ptr = malloc(3*sizeof(int));
ptr[5] = 100;
Undefined behavior.
1.15.19 Memory Leak Demonstration
Incorrect:
void test()
{
int *ptr;
ptr = malloc(100*sizeof(int));
}
Every function call leaks memory.
Correct:
void test()
{
int *ptr;
ptr = malloc(100*sizeof(int));
free(ptr);
}
1.15.20 Best Practices
Always Check Allocation
if(ptr == NULL)
{
printf("Allocation Failed");
}
Free Memory When Finished
free(ptr);
Set Pointer to NULL
free(ptr);
ptr = NULL;
Avoid Accessing Freed Memory
Incorrect:
free(ptr);
printf("%d",ptr[0]);
Allocate Exact Size
Good: malloc(n*sizeof(int));. Avoid arbitrary sizes.
1.15.21 Memory Allocation Flow
Request Memory
↓
malloc/calloc
↓
Use Memory
↓
realloc (optional)
↓
free
↓
Set Pointer NULL
1.15.22 Real-World Uses
Dynamic memory allocation is heavily used in:
- Operating Systems
- Databases
- Compilers
- Embedded Systems
- Network Applications
- Games
- Browser Engines
- Artificial Intelligence Applications
Summary
- Memory in C is managed manually.
- Stack stores local variables and function information.
- Heap stores dynamically allocated memory.
- Data Segment stores global and static variables.
- Code Segment stores executable instructions.
- malloc() allocates memory without initialization.
- calloc() allocates memory and initializes it to zero.
- realloc() changes the size of allocated memory.
- free() releases memory back to the system.
- Memory leaks, dangling pointers and buffer overflows are common errors.
- Proper memory management is essential for writing efficient and reliable C programs.
Click your choice for each question to view feedback immediately. Complete all questions to evaluate your metric score.