C ProgrammingUnit 810 min read
Pointers, Memory Management & Dynamic Allocation in C
Unit 8 of C Programming covers pointers (addresses, dereferencing, arithmetic), memory management (stack vs heap, static vs dynamic allocation), and dynamic memory allocation functions (malloc, calloc, realloc, free) with practical applications in data structures and real-world scenarios like sorting records or handlin
TAKEAWAYS:
- Pointers store memory addresses and enable direct memory manipulation, enabling efficient data structures like linked lists and dynamic arrays.
- Memory in C is divided into stack (automatic, fixed-size) and heap (dynamic, variable-size) regions, each with distinct allocation rules.
- Dynamic memory allocation (
malloc,calloc) allows runtime memory allocation for flexible data structures (e.g., arrays of unknown size). - Dangling pointers (accessing freed memory) and memory leaks (unfreed blocks) are critical bugs requiring careful pointer management.
- Pointers to structures/unions enable efficient traversal and modification of complex data (e.g., sorting employee records).
- Real-world uses include Khalti’s transaction logs (dynamic arrays for variable transactions) and Ncell’s call routing (pointer-based linked lists for call queues).
1. Pointers: The Foundation
1.1 What is a Pointer?
A pointer is a variable that stores the memory address of another variable. It allows indirect access to data, enabling efficient memory operations.
classDiagram
class Pointer {
+int* ptr
+void assign(int* address)
+int dereference() int
}
class Variable {
+int value
}
Pointer --> Variable : points toKey Operations:
- Declaration:
int *ptr;(declares a pointer to an integer). - Assignment:
ptr = &var;(stores the address ofvar). - Dereferencing:
*ptr = 10;(accesses/modifies the value at the address).
1.2 Pointer Arithmetic
Pointers can be incremented/decremented to traverse memory (e.g., arrays). Each increment moves by the size of the data type (e.g., int* moves by 4 bytes on most systems).
int arr[3] = {10, 20, 30};
int *ptr = arr; // ptr points to arr[0]
printf("%d", *(ptr + 1)); // Output: 20 (arr[1])
Visualization: Pointer Arithmetic in an Array
1.3 Special Pointers
| Type | Description | Example |
|---|---|---|
| Null Pointer | Points to nothing (address 0). Prevents undefined behavior. | int *ptr = NULL; |
| Void Pointer | Generic pointer (can point to any data type). Requires casting. | void *ptr = malloc(10); |
| Dangling Pointer | Points to freed memory. Causes crashes. | free(ptr); *ptr = 5; (dangerous) |
| Wild Pointer | Uninitialized pointer (garbage address). | int *ptr; (not assigned) |
2. Memory Management in C
2.1 Stack vs. Heap Memory
| Feature | Stack | Heap |
|---|---|---|
| Allocation | Automatic (compiler-managed) | Manual (malloc, calloc) |
| Size | Fixed (small, ~1-8 MB) | Large (limited by system) |
| Lifetime | Scope-bound (freed on block exit) | Persists until free() |
| Speed | Faster (no OS overhead) | Slower (OS allocation) |
| Use Case | Local variables, function calls | Dynamic data (arrays, structures) |
Visualization: Stack vs. Heap
2.2 Static vs. Dynamic Memory Allocation
| Static | Dynamic |
|---|---|
| Allocated at compile-time | Allocated at runtime |
| Fixed size | Variable size |
Example: int arr[10]; |
Example: int *arr = malloc(10*sizeof(int)); |
| Limitations: | Advantages: |
| - Wastes memory if size is overestimated. | - Flexible (allocates only what’s needed). |
| - Cannot resize. | - Supports complex data structures (linked lists, trees). |
3. Dynamic Memory Allocation (DMA)
flowchart TD
A["Allocate: `ptr = malloc(5*sizeof(int))`"] --> B["Store values: `ptr[0] = 10`"]
B --> C["Resize: `ptr = realloc(ptr, 10*sizeof(int))`"]
C --> D["Free: `free(ptr)`"]Lifecycle of dynamic memory allocation3.1 Key Functions
| Function | Description | Example |
|---|---|---|
malloc() |
Allocates uninitialized memory. | ptr = malloc(10 * sizeof(int)); |
calloc() |
Allocates zero-initialized memory. | ptr = calloc(10, sizeof(int)); |
realloc() |
Resizes previously allocated memory. | ptr = realloc(ptr, 20 * sizeof(int)); |
free() |
Releases allocated memory (prevents leaks). | free(ptr); |
Example: Allocating and Freeing Memory
int *arr = malloc(5 * sizeof(int)); // Allocates 5 integers
if (arr == NULL) { /* Handle error */ }
arr[0] = 10; // Store value
free(arr); // Release memory
3.2 Common Pitfalls
- Memory Leak: Forgetting to
free()allocated memory.int *ptr = malloc(100); // ... (no free(ptr)) → Leak! - Dangling Pointer: Using a pointer after
free().int *ptr = malloc(10); free(ptr); *ptr = 5; // Undefined behavior! - Wild Pointer: Using an uninitialized pointer.
int *ptr; *ptr = 10; // Crash (ptr may point to invalid memory)
Visualization: Memory Leak
4. Pointers and Structures
4.1 Pointers to Structures
Structures can be passed to functions via pointers for efficiency (avoids copying large data).
struct Employee {
int id;
char name[50];
float salary;
};
void printEmp(struct Employee *e) {
printf("ID: %d, Name: %s", e->id, e->name);
}
Example: Sorting Employee Records
#include <stdio.h>
#include <stdlib.h>
struct Employee {
int id;
char name[50];
float salary;
};
int compare(const void *a, const void *b) {
return ((struct Employee *)a)->salary - ((struct Employee *)b)->salary;
}
int main() {
struct Employee *emp = malloc(3 * sizeof(struct Employee));
emp[0] = (struct Employee){1, "Alice", 50000};
emp[1] = (struct Employee){2, "Bob", 30000};
emp[2] = (struct Employee){3, "Charlie", 70000};
qsort(emp, 3, sizeof(struct Employee), compare);
for (int i = 0; i < 3; i++)
printf("%s: %.2f\n", emp[i].name, emp[i].salary);
free(emp);
return 0;
}
Output:
Bob: 30000.00
Alice: 50000.00
Charlie: 70000.00
Visualization: Structure with Pointer
. (Image: Qwertyus, CC BY-SA 4.0, via Wikimedia Commons)")
5. Real-World Applications
In the Real World
Khalti’s Transaction Logs
- Idea Used: Dynamic arrays (pointer-based) to store variable numbers of transactions.
- How:
malloc()allocates memory for each new transaction, andrealloc()resizes the log as needed.
Ncell’s Call Routing System
- Idea Used: Linked lists (pointers to
struct Call) to manage call queues. - How: Each call is a node with
nextpointer, enabling efficient FIFO processing.
- Idea Used: Linked lists (pointers to
Daraz’s Order Processing
- Idea Used: Pointers to structures (
struct Order) for tracking orders. - How:
malloc()creates an order record, andfree()clears completed orders.
- Idea Used: Pointers to structures (
Worked Example: Bank Loan Interest Calculation
#include <stdio.h>
float calculateInterest(float *principal, float rate, int years) {
return (*principal * rate * years) / 100;
}
int main() {
float principal = 100000;
float rate = 5.5;
int years = 3;
float interest = calculateInterest(&principal, rate, years);
printf("Interest: %.2f\n", interest); // Output: 16500.00
return 0;
}
Trace Table:
| Step | principal |
rate |
years |
interest Calculation |
|---|---|---|---|---|
| 1 | 100000 | 5.5 | 3 | (100000 * 5.5 * 3) / 100 = 16500 |
6. Exam Tip
- Pointer Syntax: Always declare pointers correctly (
int *ptr;notint* ptr;unless intentional). - DMA Functions: Remember:
malloc(): Uninitialized.calloc(): Zero-initialized.realloc(): Resizes existing memory.free(): Always free dynamically allocated memory.
- Common Exam Questions:
- Write a program to swap two numbers using pointers.
- Explain dangling pointers and how to avoid them.
- Use
malloc()to store N integers and find the sum.
- Avoid Memory Leaks: In programs using
malloc, ensure every allocation has a correspondingfree(). - Pointer Arithmetic: Understand how
ptr + 1behaves differently forint*vschar*.
Key Formula (Interest Calculation):
In the real world
- Khalti’s Transaction Logs: Uses dynamic arrays (resizable via
realloc) to store variable-length transaction records (e.g.,struct Transaction *logs = malloc(N*sizeof(struct Transaction))), whereNgrows with new payments. Each transaction pointer (logs[i]) holds merchant ID, amount, and timestamp. - Ncell’s Call Routing: Implements linked lists (via
struct CallNode *next) to manage call queues dynamically. When a call arrives, a new node ismalloc’d and appended to the queue’srear, while thefrontnode isfree’d when the call ends. - Nepali Banks’ Loan Processing: Employs pointers to structures (e.g.,
struct Loan *loans = malloc(1000*sizeof(struct Loan))) to track borrower details (ID, amount, interest rate) and sort them by priority usingqsortwith a custom comparator.
Based on the TU BCA syllabus for C Programming (CACS151), unit 8.
Discussion
Loading…