Experiment 14 – Dynamic Memory Allocation
Aim
To understand and implement dynamic memory allocation using malloc(),calloc(), realloc(), and free() functions in C programming. Learn to allocate memory at runtime and prevent memory leaks. This experiment helps students understand heap memory, dynamic data structures, and proper resource management.
Through this experiment, students will learn to allocate memory dynamically, understand the difference between stack and heap memory, implement proper memory management, and prevent memory leaks that can cause program failures.
Learning Outcomes
After completing this experiment, students will be able to:
- Allocate memory dynamically using malloc() and calloc()
- Resize allocated memory using realloc()
- Deallocate memory using free() to prevent leaks
- Check for allocation failures (NULL pointer)
- Understand the difference between malloc() and calloc()
- Handle memory allocation errors gracefully
- Set pointers to NULL after freeing to avoid dangling pointers
- Create dynamic arrays and data structures
Algorithm
The algorithm for dynamic memory allocation involves allocation, usage, and deallocation:
Dynamic Memory Allocation Algorithm:
- Allocate Memory:
- malloc:
ptr = (type*)malloc(n * sizeof(type)) - calloc:
ptr = (type*)calloc(n, sizeof(type))
- malloc:
- Check Allocation: If
ptr == NULL, allocation failed, handle error - Use Memory: Access allocated memory using pointer (ptr[i] or *(ptr + i))
- Resize (Optional):
ptr = realloc(ptr, new_size), check for NULL - Deallocate:
free(ptr)when done - Set to NULL:
ptr = NULLto prevent dangling pointer
Critical Rules: Always check for NULL after allocation, always free allocated memory, never use freed memory, set pointer to NULL after freeing, match malloc with free, calloc with free, realloc with free.
Procedure
- Include
stdio.handstdlib.hheader files - For malloc():
- Allocates memory of specified size
- Returns pointer to allocated memory
- Memory contains garbage values
- Syntax:
ptr = (type*)malloc(size)
- For calloc():
- Allocates memory and initializes to zero
- Syntax:
ptr = (type*)calloc(n, size)
- For realloc():
- Resizes previously allocated memory
- Syntax:
ptr = realloc(ptr, new_size)
- Always check if allocation was successful (ptr != NULL)
- Use
free(ptr)to deallocate memory - Set pointer to NULL after freeing to avoid dangling pointers
Flowchart
START │ ├─→ Declare: int *ptr, n │ ├─→ Read n (number of elements) │ ├─→ ptr = (int*)malloc(n * sizeof(int)) │ ├─→ IF (ptr == NULL) │ │ │ └─→ Display "Memory allocation failed" │ └─→ EXIT │ ├─→ Read elements into dynamically allocated array │ ├─→ Display array elements │ ├─→ ptr = realloc(ptr, (n+2) * sizeof(int)) │ ├─→ Add more elements │ ├─→ Display updated array │ ├─→ free(ptr) ├─→ ptr = NULL │ └─→ END
Program Code
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr_malloc, *arr_calloc, *arr_realloc;
int n, i, new_size;
printf("Enter number of elements: ");
scanf("%d", &n);
// Using malloc() - allocates memory, contains garbage values
arr_malloc = (int*)malloc(n * sizeof(int));
if (arr_malloc == NULL) {
printf("Memory allocation failed using malloc!\n");
return 1;
}
printf("\n--- Using malloc() ---\n");
printf("Enter %d elements:\n", n);
for (i = 0; i < n; i++) {
printf("Element %d: ", i + 1);
scanf("%d", &arr_malloc[i]);
}
printf("Array elements (malloc): ");
for (i = 0; i < n; i++) {
printf("%d ", arr_malloc[i]);
}
printf("\n");
// Using calloc() - allocates memory, initializes to zero
arr_calloc = (int*)calloc(n, sizeof(int));
if (arr_calloc == NULL) {
printf("Memory allocation failed using calloc!\n");
free(arr_malloc); // Free previously allocated memory
return 1;
}
printf("\n--- Using calloc() ---\n");
printf("Array elements (calloc - initialized to zero): ");
for (i = 0; i < n; i++) {
printf("%d ", arr_calloc[i]);
}
printf("\n");
printf("Enter %d elements for calloc array:\n", n);
for (i = 0; i < n; i++) {
printf("Element %d: ", i + 1);
scanf("%d", &arr_calloc[i]);
}
printf("Array elements (calloc after input): ");
for (i = 0; i < n; i++) {
printf("%d ", arr_calloc[i]);
}
printf("\n");
// Using realloc() - resize previously allocated memory
printf("\n--- Using realloc() ---\n");
printf("Enter new size (larger than %d): ", n);
scanf("%d", &new_size);
arr_realloc = (int*)realloc(arr_malloc, new_size * sizeof(int));
if (arr_realloc == NULL) {
printf("Memory reallocation failed!\n");
free(arr_malloc);
free(arr_calloc);
return 1;
}
// If realloc moved the memory, arr_malloc is now invalid
// Use arr_realloc instead
printf("Enter %d more elements:\n", new_size - n);
for (i = n; i < new_size; i++) {
printf("Element %d: ", i + 1);
scanf("%d", &arr_realloc[i]);
}
printf("Array elements after realloc (size %d): ", new_size);
for (i = 0; i < new_size; i++) {
printf("%d ", arr_realloc[i]);
}
printf("\n");
// Free all allocated memory
printf("\n--- Freeing Memory ---\n");
free(arr_realloc); // Free reallocated memory (or original malloc)
arr_realloc = NULL; // Set to NULL to avoid dangling pointer
free(arr_calloc);
arr_calloc = NULL;
printf("Memory freed successfully!\n");
return 0;
}
// Key Points:
// 1. Always check if malloc/calloc/realloc returns NULL
// 2. Always free dynamically allocated memory
// 3. Set pointer to NULL after freeing
// 4. malloc() - uninitialized memory
// 5. calloc() - zero-initialized memory
// 6. realloc() - can move memory to new locationSample Input and Output
Sample 1:
Input:
Enter number of elements: 3 --- Using malloc() --- Enter 3 elements: Element 1: 10 Element 2: 20 Element 3: 30 Array elements (malloc): 10 20 30 --- Using calloc() --- Array elements (calloc - initialized to zero): 0 0 0 Enter 3 elements for calloc array: Element 1: 40 Element 2: 50 Element 3: 60 Array elements (calloc after input): 40 50 60 --- Using realloc() --- Enter new size (larger than 3): 5 Enter 2 more elements: Element 4: 70 Element 5: 80 Array elements after realloc (size 5): 10 20 30 70 80 --- Freeing Memory --- Memory freed successfully!
Use Case / Real-world Relevance
Dynamic memory allocation is essential for flexible and efficient programs:
- Data Structures: Implementing linked lists, trees, graphs, and dynamic arrays
- Variable-Sized Data: Handling data whose size is unknown at compile time
- Memory Efficiency: Allocating only as much memory as needed
- System Programming: Operating systems, device drivers, and low-level programming
- Application Development: Building flexible applications that adapt to user needs
- Performance Optimization: Reducing memory waste and improving efficiency
- Embedded Systems: Managing limited memory resources efficiently
- Game Development: Dynamic loading of game assets, level data
Understanding dynamic memory management is crucial for preventing memory leaks, which can cause programs to consume excessive memory and eventually crash. Proper memory management is a hallmark of professional programming.
Important: Always free dynamically allocated memory to prevent memory leaks. Memory leaks occur when allocated memory is not freed, causing the program to consume more and more memory over time. In long-running programs, this can exhaust system memory and cause crashes.
Viva Questions
Q1: What is the difference between malloc() and calloc()?
malloc(n * size) allocates n*size bytes, memory contains garbage values.calloc(n, size) allocates n*size bytes and initializes all bytes to zero. calloc is slower (initialization overhead) but safer (no garbage values). Use malloc when you'll initialize yourself, calloc when you need zero-initialized memory.
Q2: What happens if we don't free dynamically allocated memory?
Memory leak occurs - allocated memory is never returned to system, program consumes increasing memory. In short programs, OS reclaims memory on exit, but in long-running programs (servers, daemons), leaks cause memory exhaustion and crashes. Always free memory to prevent leaks. Use tools like valgrind to detect leaks.
Q3: What is a dangling pointer and how do we prevent it?
Dangling pointer points to memory that has been freed. Using it causes undefined behavior. Prevent by setting pointer to NULL after free: free(ptr); ptr = NULL;. This makes it safe to check (if (ptr != NULL)) and prevents accidental use. Accessing NULL pointer causes segmentation fault (detectable) vs undefined behavior from dangling pointer.
Q4: How does realloc() work and when might it fail?
realloc() resizes previously allocated memory. It may extend existing block (if space available) or allocate new block and copy data. Returns new pointer (may be different from old). Fails if insufficient memory, returns NULL. Important: don't lose old pointer until checking if realloc succeeded. If realloc fails, original memory is still valid. Always check return value before using.
Q5: What is the difference between stack and heap memory?
Stack: automatic storage for local variables, managed by compiler, fast, limited size, automatically freed when function returns. Heap: dynamic memory allocated with malloc/calloc, managed manually, larger size, slower, must be explicitly freed. Stack is for fixed-size local data, heap is for dynamic/variable-size data that outlives function scope.
Q6: Can we free the same memory twice?
No, double free causes undefined behavior, often crashes. Freeing already-freed memory or freeing memory not allocated with malloc/calloc/realloc is dangerous. Always set pointer to NULL after free, and check before freeing: if (ptr != NULL) free(ptr);. Freeing NULL is safe (does nothing), so setting to NULL after free prevents double-free errors.
Q7: What happens if malloc() returns NULL?
NULL means allocation failed (insufficient memory, heap fragmentation, system limits). Using NULL pointer causes segmentation fault. Always check: if (ptr == NULL) . Options: exit program, return error code, try smaller allocation, or free other memory and retry. Never dereference NULL pointer.
Q8: Why do we need to cast the return value of malloc()?
In C, malloc() returns void* (generic pointer). Casting to specific type ((int*)malloc(...)) makes code clearer and helps catch type errors. In C++, casting is required (C++ doesn't allow implicit void* conversion). However, in modern C, casting is optional but recommended for clarity and compatibility.
Related Links
🔹 Author: Dr. J. Siva Ramakrishna
🔹 Institution: Narayana Engineering College, Gudur
🔹 Last Updated: 9 January 2026