C ProgrammingUnit 812 min read
Pointers, Dynamic Memory & Memory Management in C
Unit 8 of C Programming covers pointers (addresses, dereferencing, pointer arithmetic), dynamic memory allocation (malloc, calloc, realloc, free), memory leaks, dangling pointers, and real-world applications in data structures and system-level programming.
TAKEAWAYS:
- Pointers store memory addresses and enable indirect access to variables, enabling efficient data manipulation and dynamic memory handling.
- Dynamic memory allocation (
malloc,calloc) allows runtime memory allocation, whilefreedeallocates it to prevent memory leaks. - Pointer arithmetic and arrays are deeply connected, enabling efficient traversal and manipulation of contiguous memory blocks.
- Common pitfalls like dangling pointers, memory leaks, and wild pointers must be avoided for robust programs.
- Dynamic memory is essential for implementing data structures like linked lists, trees, and graphs in C.
- Understanding memory management is critical for writing efficient and secure programs, especially in system-level applications.
Pointers: The Foundation of Dynamic Memory
Pointers are variables that store memory addresses instead of values. They are fundamental in C for dynamic memory allocation, efficient data manipulation, and implementing complex data structures.
How Pointers Work
A pointer variable holds the address of another variable. To declare a pointer:
int *ptr; // ptr is a pointer to an integer
*before a variable name declares it as a pointer.&(address-of operator) gives the memory address of a variable.*(dereference operator) accesses the value at the address stored in a pointer.
Example: Basic Pointer Operations
#include <stdio.h>
int main() {
int x = 10;
int *ptr = &x; // ptr now holds the address of x
printf("Address of x: %p\n", (void*)&x);
printf("Value of ptr: %p\n", (void*)ptr);
printf("Value of *ptr: %d\n", *ptr); // Dereferencing ptr
*ptr = 20; // Changing x through ptr
printf("New value of x: %d\n", x);
return 0;
}
Trace Table:
| Step | x |
ptr (address) |
*ptr (value) |
|---|---|---|---|
| Initial | 10 | NULL | - |
ptr = &x |
10 | Address of x | 10 |
*ptr = 20 |
20 | Address of x | 20 |
Pointer Arithmetic
Pointer arithmetic allows traversal of arrays and contiguous memory blocks. For example:
int arr[3] = {10, 20, 30};
int *ptr = arr; // ptr points to the first element
```figure
{"type":"array","values":[10,20,30,40,50],"highlight":[1],"pointers":{"0":"ptr (points to arr[0])","1":"ptr + 1 (points to arr[1])"},"caption":"Pointer arithmetic: `ptr + 1` moves to the next integer (address +4 bytes)."}
printf("%d\n", *(ptr + 1)); // Output: 20 (equivalent to arr[1]) Key Rules:
- Pointer arithmetic is valid only for pointers to elements of the same array or dynamically allocated contiguous memory.
ptr + 1moves the pointer bysizeof(*ptr)bytes (e.g., 4 bytes forinton most systems).
Dynamic Memory Allocation
Dynamic memory allocation allows programs to request memory at runtime using functions from <stdlib.h>:
malloc: Allocates memory but does not initialize it.calloc: Allocates and initializes memory to zero.realloc: Resizes previously allocated memory.free: Deallocates memory to avoid leaks.
Example: Allocating an Array Dynamically
#include <stdio.h>
#include <stdlib.h>
```figure
{"type":"array","values":[1,2,3,null,null],"highlight":[0,1,2],"pointers":{"0":"arr (dynamically allocated)"},"caption":"State after `malloc(5 * sizeof(int))` and initialization: first 3 elements set to 1, 2, 3."}
int main() { int n, *arr;
printf("Enter size: ");
scanf("%d", &n);
// Allocate memory for n integers
arr = (int*)malloc(n * sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
// Initialize and print
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
printf("%d ", arr[i]);
}
// Free the allocated memory
free(arr);
return 0;
} Trace Table:
| Step | arr (address) |
Memory Contents (first 3) |
|---|---|---|
After malloc |
Address X | Garbage, Garbage, Garbage |
| After initialization | Address X | 1, 2, 3 |
After free |
Address X | (Memory is freed) |
Common Pitfalls and Best Practices
1. Memory Leaks
Occur when dynamically allocated memory is not freed, wasting system resources. Example:
int *ptr = malloc(10 * sizeof(int));
// Forgetting to free(ptr) causes a leak.
2. Dangling Pointers
Pointers that reference memory that has already been freed. Example:
int *ptr = malloc(sizeof(int));
free(ptr);
*ptr = 5; // Undefined behavior (dangling pointer)
3. Wild Pointers
Pointers that are uninitialized or point to invalid memory. Example:
int *ptr; // Wild pointer
printf("%d", *ptr); // Undefined behavior
Best Practices:
- Always check if
malloc/callocreturnsNULL. - Free memory when it is no longer needed.
- Initialize pointers to
NULLbefore use. - Use tools like Valgrind to detect memory leaks.
Pointers and Arrays
Arrays and pointers are closely related in C. The name of an array decays into a pointer to its first element. Example:
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // ptr points to arr[0]
printf("%d\n", *(ptr + 2)); // Output: 3 (equivalent to arr[2])
Key Insight:
graph LR
A["int arr[5]"] --> B["&arr[0]"]
B --> C["arr (decays to pointer)"]
C --> D["ptr = arr"]
D --> E["ptr + i = &arr[i]"]
E --> F["*(ptr + i) = arr[i]"]Real-World Applications
1. eSewa (Nepal)
- Idea Used: Dynamic memory allocation for handling variable-sized transaction records.
- How: eSewa processes thousands of transactions per second. Dynamic arrays (resizable using
realloc) store transaction data efficiently, allowing the system to scale without predefined limits.
2. Khalti (Nepal)
- Idea Used: Pointers for efficient data structure manipulation in fraud detection algorithms.
- How: Khalti uses linked lists (implemented with pointers) to maintain a queue of pending transactions. Each transaction node contains a pointer to the next transaction, enabling efficient insertion and deletion.
3. Pathao (Nepal)
- Idea Used: Dynamic memory for real-time route optimization.
- How: Pathao’s algorithm dynamically allocates memory for graph nodes (representing locations) and edges (representing routes). Pointers are used to traverse the graph and find the shortest path using Dijkstra’s algorithm.
4. Bank Loan Calculations (Nepal)
- Idea Used: Pointers for efficient computation of loan installments.
- How: Banks use dynamic arrays to store loan schedules. For a loan of ₹1,000,000 at 10% interest over 5 years, the program dynamically allocates memory for 60 monthly installments and calculates each using pointer arithmetic:
float *installments = malloc(60 * sizeof(float)); float principal = 1000000.0; float rate = 0.10 / 12; for (int i = 0; i < 60; i++) { installments[i] = (principal * rate) / (1 - pow(1 + rate, -60)); }
Data Structures Using Pointers
Pointers are essential for implementing dynamic data structures like linked lists, trees, and graphs.
Example: Singly Linked List
#include <stdio.h>
#include <stdlib.h>
```mermaid
graph LR
A[10] --> B[20]
B --> C[30]
style B fill:#f9f,stroke:#333
caption: Linked list structure with `head` pointing to 10.
Pointer relationships in a singly linked list (head → 10 → 20 → 30).
struct Node { int data; struct Node *next; };
void insertEnd(struct Node **head, int data) { struct Node *newNode = malloc(sizeof(struct Node)); newNode->data = data; newNode->next = NULL;
if (*head == NULL) {
*head = newNode;
} else {
struct Node *temp = *head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
}
void printList(struct Node *head) { while (head != NULL) { printf("%d -> ", head->data); head = head->next; } printf("NULL\n"); }
int main() { struct Node *head = NULL; insertEnd(&head, 10); insertEnd(&head, 20); insertEnd(&head, 30); printList(head); // Output: 10 -> 20 -> 30 -> NULL return 0; }
**State After Each Insertion:**
```mermaid
graph LR
A["After insert 10"] --> B["10 -> NULL"]
B --> C["After insert 20"]
C --> D["10 -> 20 -> NULL"]
D --> E["After insert 30"]
E --> F["10 -> 20 -> 30 -> NULL"]
In the real world
Pathao (Nepal): Uses pointers to graph nodes in Dijkstra’s algorithm to dynamically update shortest paths between rider locations and pickup points. For example, when a rider requests a ride from Thapathali to Boudhanath, Pathao’s backend allocates memory for graph nodes (e.g.,
Thapathali,Kathmandu Durbar Square,Boudhanath) and edges (e.g.,Thapathali → Durbar Square: 5 min), then traverses the graph using pointers to compute the optimal route.Nepal Rastra Bank: Implements dynamic arrays with pointers to store loan installment schedules. For a ₹500,000 loan at 9% over 10 years, the bank’s system allocates memory for 120 installments (₹5,805.30 each) and uses pointer arithmetic to calculate each month’s principal/interest split.
Ncell (Nepal): Uses linked lists (pointer-based) to manage call logs. When a user makes a call to 01-4234567, Ncell appends a new node to the linked list (containing caller ID, timestamp, duration) and updates the
headpointer. This allows efficient insertion/deletion without resizing arrays.
Exam Tip
What to Expect:
Pointer Arithmetic Questions:
- Expect questions on how pointer arithmetic works with arrays (e.g.,
*(ptr + i)vs.ptr[i]). - Example: Given
int arr[3] = {5, 10, 15}; int *ptr = arr;, what does*(ptr + 1) + *(arr + 2)evaluate to? (Answer:10 + 15 = 25).
- Expect questions on how pointer arithmetic works with arrays (e.g.,
Dynamic Memory Allocation:
- Questions may ask you to write code for allocating, initializing, and freeing memory.
- Example: Write a function to allocate memory for an array of
nintegers and initialize all elements to0.
Debugging Pitfalls:
- Identify memory leaks, dangling pointers, or wild pointers in given code snippets.
- Example: Given a code snippet with
mallocbut nofree, explain the memory leak.
Pointers and Structures:
- Questions on traversing or modifying linked lists, trees, or graphs using pointers.
- Example: Write a function to reverse a singly linked list using pointers.
Real-World Scenarios:
- Apply concepts to practical scenarios like managing queues (e.g., Daraz order processing) or graphs (e.g., NTC traffic route optimization).
- Example: Explain how dynamic memory allocation helps in implementing a priority queue for a hospital’s patient management system.
Key Formulas to Remember:
- Size of dynamically allocated memory:
n * sizeof(data_type). - Pointer arithmetic:
ptr + imovesi * sizeof(*ptr)bytes. - Address of an array element:
&arr[i]orarr + i.
Common Mistakes to Avoid:
- Forgetting to free dynamically allocated memory.
- Dereferencing
NULLpointers or uninitialized pointers. - Assuming
mallocalways succeeds (always check forNULL). - Modifying pointers after freeing the memory they point to.
Final Worked Example: Bank Loan Amortization Schedule
Problem: Write a program to generate an amortization schedule for a loan of ₹500,000 at 8% annual interest over 5 years. Use dynamic memory to store monthly payments.
Solution:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void generateAmortizationSchedule(float principal, float rate, int years) {
int months = years * 12;
float monthlyRate = rate / 1200; // Convert annual rate to monthly
float monthlyPayment = (principal * monthlyRate) / (1 - pow(1 + monthlyRate, -months));
// Allocate memory for the schedule
float *schedule = malloc(months * sizeof(float));
if (schedule == NULL) {
printf("Memory allocation failed!\n");
return;
}
float remaining = principal;
printf("Month\tPayment\tPrincipal\tInterest\tRemaining\n");
for (int i = 0; i < months; i++) {
float interest = remaining * monthlyRate;
float principalPart = monthlyPayment - interest;
schedule[i] = remaining - principalPart;
remaining = schedule[i];
printf("%d\t%.2f\t%.2f\t\t%.2f\t\t%.2f\n",
i + 1, monthlyPayment, principalPart, interest, remaining);
}
free(schedule);
}
int main() {
generateAmortizationSchedule(500000, 8, 5);
return 0;
}
Output (First 3 Months):
| Month | Payment | Principal | Interest | Remaining |
|---|---|---|---|---|
| 1 | 9,774.50 | 8,333.33 | 1,441.17 | 491,666.67 |
| 2 | 9,774.50 | 8,366.67 | 1,407.83 | 483,300.00 |
| 3 | 9,774.50 | 8,400.00 | 1,374.50 | 474,900.00 |
Key Insight:
- The
schedulearray dynamically stores the remaining balance for each month. - Pointer arithmetic and dynamic memory ensure the program works for any loan term without predefined limits.
Based on the TU BIM syllabus for C Programming (IT232), unit 8.
Discussion
Loading…