c
examples
examples.cš§c
/**
* Dynamic Memory Allocation - Examples
*
* This file demonstrates malloc, calloc, realloc, and free functions
* for dynamic memory management in C.
*
* Compile: gcc examples.c -o examples
* Run: ./examples
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ============================================================
* EXAMPLE 1: malloc() - Basic Memory Allocation
* ============================================================ */
void example1_malloc_basics(void) {
printf("=== EXAMPLE 1: malloc() Basics ===\n\n");
// Allocate memory for a single integer
int *ptr = (int *)malloc(sizeof(int));
if (ptr == NULL) {
printf("Memory allocation failed!\n");
return;
}
printf("Single integer allocation:\n");
printf(" Address allocated: %p\n", (void *)ptr);
printf(" Size allocated: %zu bytes\n\n", sizeof(int));
// Store a value
*ptr = 42;
printf(" Value stored: %d\n", *ptr);
// Always free allocated memory
free(ptr);
printf(" Memory freed successfully.\n\n");
// Allocate memory for an array of 5 integers
int *arr = (int *)malloc(5 * sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed!\n");
return;
}
printf("Array of 5 integers:\n");
printf(" Total size: %zu bytes\n", 5 * sizeof(int));
// Initialize and display values
for (int i = 0; i < 5; i++) {
arr[i] = (i + 1) * 10; // 10, 20, 30, 40, 50
}
printf(" Values: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
printf(" Memory freed successfully.\n");
}
/* ============================================================
* EXAMPLE 2: malloc() - Memory Contains Garbage Values
* ============================================================ */
void example2_malloc_garbage(void) {
printf("\n=== EXAMPLE 2: malloc() Contains Garbage ===\n\n");
int *arr = (int *)malloc(5 * sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed!\n");
return;
}
printf("Memory allocated but NOT initialized:\n");
printf("Values (garbage): ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // Unpredictable values!
}
printf("\n\n");
printf("WARNING: Always initialize malloc'd memory before use!\n");
// Proper initialization
for (int i = 0; i < 5; i++) {
arr[i] = 0;
}
printf("After initialization: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
}
/* ============================================================
* EXAMPLE 3: calloc() - Zero-Initialized Memory
* ============================================================ */
void example3_calloc(void) {
printf("\n=== EXAMPLE 3: calloc() - Zero-Initialized ===\n\n");
// calloc(count, size) - allocates and initializes to zero
int *arr = (int *)calloc(5, sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed!\n");
return;
}
printf("Syntax: calloc(number_of_elements, size_of_each)\n\n");
printf("Allocated 5 integers with calloc:\n");
printf("Values (auto-initialized to 0): ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // All zeros!
}
printf("\n\n");
// Modify values
for (int i = 0; i < 5; i++) {
arr[i] = i * i; // 0, 1, 4, 9, 16
}
printf("After modification: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
}
/* ============================================================
* EXAMPLE 4: malloc() vs calloc() Comparison
* ============================================================ */
void example4_malloc_vs_calloc(void) {
printf("\n=== EXAMPLE 4: malloc() vs calloc() ===\n\n");
printf("āāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf("ā Feature ā malloc() ā calloc() ā\n");
printf("āāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤\n");
printf("ā Syntax ā malloc(size_in_bytes) ā calloc(count, size_of_each) ā\n");
printf("ā Arguments ā 1 argument ā 2 arguments ā\n");
printf("ā Initialize ā NO (garbage values) ā YES (zeros) ā\n");
printf("ā Speed ā Slightly faster ā Slightly slower ā\n");
printf("āāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n\n");
// Practical demonstration
printf("Practical demonstration:\n\n");
// malloc way
int *m = (int *)malloc(3 * sizeof(int));
if (m) {
printf("malloc(3 * sizeof(int)): ");
printf("[%d, %d, %d] (garbage)\n", m[0], m[1], m[2]);
free(m);
}
// calloc way
int *c = (int *)calloc(3, sizeof(int));
if (c) {
printf("calloc(3, sizeof(int)): ");
printf("[%d, %d, %d] (zeros)\n", c[0], c[1], c[2]);
free(c);
}
}
/* ============================================================
* EXAMPLE 5: realloc() - Resize Allocated Memory
* ============================================================ */
void example5_realloc(void) {
printf("\n=== EXAMPLE 5: realloc() - Resize Memory ===\n\n");
// Start with 3 integers
int *arr = (int *)malloc(3 * sizeof(int));
if (arr == NULL) return;
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
printf("Initial allocation (3 integers):\n");
printf(" Address: %p\n", (void *)arr);
printf(" Values: [%d, %d, %d]\n\n", arr[0], arr[1], arr[2]);
// Expand to 5 integers
int *new_arr = (int *)realloc(arr, 5 * sizeof(int));
if (new_arr == NULL) {
printf("Reallocation failed! Original memory intact.\n");
free(arr);
return;
}
arr = new_arr; // Update pointer
printf("After realloc to 5 integers:\n");
printf(" Address: %p %s\n", (void *)arr,
(arr == new_arr) ? "(might be same or different)" : "");
printf(" Old values preserved: [%d, %d, %d, ?, ?]\n",
arr[0], arr[1], arr[2]);
// Initialize new elements
arr[3] = 40;
arr[4] = 50;
printf(" After initialization: [%d, %d, %d, %d, %d]\n\n",
arr[0], arr[1], arr[2], arr[3], arr[4]);
// Shrink to 2 integers
int *smaller = (int *)realloc(arr, 2 * sizeof(int));
if (smaller) {
arr = smaller;
printf("After shrinking to 2 integers:\n");
printf(" Values: [%d, %d]\n", arr[0], arr[1]);
}
free(arr);
printf("\nMemory freed.\n");
}
/* ============================================================
* EXAMPLE 6: realloc() Special Cases
* ============================================================ */
void example6_realloc_special(void) {
printf("\n=== EXAMPLE 6: realloc() Special Cases ===\n\n");
// Case 1: realloc(NULL, size) == malloc(size)
printf("Case 1: realloc(NULL, size) acts like malloc(size)\n");
int *ptr1 = (int *)realloc(NULL, 3 * sizeof(int));
if (ptr1) {
ptr1[0] = 100;
printf(" Allocated and assigned: ptr1[0] = %d\n", ptr1[0]);
free(ptr1);
}
// Case 2: realloc(ptr, 0) - may free memory (implementation defined)
printf("\nCase 2: realloc(ptr, 0)\n");
printf(" Behavior is implementation-defined in C11+\n");
printf(" Don't rely on this - use free() explicitly!\n");
// Case 3: realloc can move memory
printf("\nCase 3: realloc may move memory to a new location\n");
int *original = (int *)malloc(2 * sizeof(int));
if (original) {
original[0] = 1;
original[1] = 2;
printf(" Original address: %p\n", (void *)original);
// Request much larger size - likely to move
int *resized = (int *)realloc(original, 1000 * sizeof(int));
if (resized) {
printf(" New address: %p\n", (void *)resized);
printf(" Data preserved: [%d, %d]\n", resized[0], resized[1]);
// Don't use 'original' anymore - it's invalid!
free(resized);
}
}
}
/* ============================================================
* EXAMPLE 7: free() and Dangling Pointers
* ============================================================ */
void example7_free_dangling(void) {
printf("\n=== EXAMPLE 7: free() and Dangling Pointers ===\n\n");
int *ptr = (int *)malloc(sizeof(int));
if (ptr == NULL) return;
*ptr = 42;
printf("Before free:\n");
printf(" ptr = %p\n", (void *)ptr);
printf(" *ptr = %d\n\n", *ptr);
free(ptr);
printf("After free(ptr):\n");
printf(" ptr still contains address: %p (dangling!)\n", (void *)ptr);
printf(" But accessing *ptr is UNDEFINED BEHAVIOR!\n\n");
// Best practice: Set to NULL after freeing
ptr = NULL;
printf("Best practice - set to NULL after free:\n");
printf(" ptr = %p (NULL - safe)\n", (void *)ptr);
printf(" Now we can check: if (ptr != NULL) before use\n");
}
/* ============================================================
* EXAMPLE 8: Common Memory Allocation Patterns
* ============================================================ */
void example8_patterns(void) {
printf("\n=== EXAMPLE 8: Common Patterns ===\n\n");
// Pattern 1: Allocate and check immediately
printf("Pattern 1: Allocate + Check + Use + Free\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
int *data = (int *)malloc(10 * sizeof(int));
if (data == NULL) {
fprintf(stderr, "Error: Memory allocation failed\n");
return;
}
// Use the memory
for (int i = 0; i < 10; i++) {
data[i] = i * 2;
}
printf(" Allocated and used 10 integers\n");
// Clean up
free(data);
data = NULL;
printf(" Freed and nullified pointer\n\n");
// Pattern 2: Dynamic string
printf("Pattern 2: Dynamic String\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
const char *source = "Hello, Dynamic Memory!";
size_t len = strlen(source) + 1; // +1 for null terminator
char *str = (char *)malloc(len);
if (str) {
strcpy(str, source);
printf(" Dynamic string: \"%s\"\n", str);
printf(" Length: %zu (including null)\n", len);
free(str);
}
// Pattern 3: Array of structures
printf("\nPattern 3: Array of Structures\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
typedef struct {
int id;
char name[20];
} Student;
int count = 3;
Student *students = (Student *)malloc(count * sizeof(Student));
if (students) {
students[0] = (Student){1, "Alice"};
students[1] = (Student){2, "Bob"};
students[2] = (Student){3, "Charlie"};
for (int i = 0; i < count; i++) {
printf(" Student %d: %s\n", students[i].id, students[i].name);
}
free(students);
}
}
/* ============================================================
* EXAMPLE 9: Dynamic 2D Array Allocation
* ============================================================ */
void example9_2d_array(void) {
printf("\n=== EXAMPLE 9: Dynamic 2D Array ===\n\n");
int rows = 3, cols = 4;
// Method 1: Array of pointers
printf("Method 1: Array of Pointers (rows Ć cols = %d Ć %d)\n", rows, cols);
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
// Allocate array of row pointers
int **matrix = (int **)malloc(rows * sizeof(int *));
if (matrix == NULL) return;
// Allocate each row
for (int i = 0; i < rows; i++) {
matrix[i] = (int *)malloc(cols * sizeof(int));
if (matrix[i] == NULL) {
// Cleanup on failure
for (int j = 0; j < i; j++) {
free(matrix[j]);
}
free(matrix);
return;
}
}
// Initialize with values
int value = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = value++;
}
}
// Display
printf("\nMatrix contents:\n");
for (int i = 0; i < rows; i++) {
printf(" ");
for (int j = 0; j < cols; j++) {
printf("%3d ", matrix[i][j]);
}
printf("\n");
}
// Free memory (reverse order)
for (int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
printf("\nMemory freed successfully.\n");
// Method 2: Single contiguous block
printf("\nMethod 2: Single Contiguous Block\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
int *flat = (int *)malloc(rows * cols * sizeof(int));
if (flat == NULL) return;
// Initialize
for (int i = 0; i < rows * cols; i++) {
flat[i] = i + 1;
}
// Access as 2D: flat[i * cols + j]
printf("\nMatrix (single block, accessed as 2D):\n");
for (int i = 0; i < rows; i++) {
printf(" ");
for (int j = 0; j < cols; j++) {
printf("%3d ", flat[i * cols + j]);
}
printf("\n");
}
free(flat);
printf("\nAdvantage: Single allocation, better cache locality.\n");
}
/* ============================================================
* EXAMPLE 10: Dynamic Array Growth (Like Vector)
* ============================================================ */
typedef struct {
int *data;
size_t size; // Current number of elements
size_t capacity; // Total allocated capacity
} DynamicArray;
DynamicArray* da_create(size_t initial_capacity) {
DynamicArray *da = (DynamicArray *)malloc(sizeof(DynamicArray));
if (da == NULL) return NULL;
da->data = (int *)malloc(initial_capacity * sizeof(int));
if (da->data == NULL) {
free(da);
return NULL;
}
da->size = 0;
da->capacity = initial_capacity;
return da;
}
int da_push(DynamicArray *da, int value) {
if (da->size >= da->capacity) {
// Double the capacity
size_t new_capacity = da->capacity * 2;
int *new_data = (int *)realloc(da->data, new_capacity * sizeof(int));
if (new_data == NULL) return 0; // Failed
da->data = new_data;
da->capacity = new_capacity;
}
da->data[da->size++] = value;
return 1; // Success
}
void da_destroy(DynamicArray *da) {
if (da) {
free(da->data);
free(da);
}
}
void example10_dynamic_growth(void) {
printf("\n=== EXAMPLE 10: Dynamic Array Growth ===\n\n");
printf("Creating a vector-like dynamic array:\n\n");
DynamicArray *arr = da_create(2); // Start with capacity 2
if (arr == NULL) return;
printf("Initial: size=0, capacity=2\n\n");
// Add elements and watch it grow
for (int i = 1; i <= 10; i++) {
size_t old_cap = arr->capacity;
da_push(arr, i * 10);
if (arr->capacity > old_cap) {
printf("Pushed %3d ā size=%zu, capacity GREW: %zu ā %zu\n",
i * 10, arr->size, old_cap, arr->capacity);
} else {
printf("Pushed %3d ā size=%zu, capacity=%zu\n",
i * 10, arr->size, arr->capacity);
}
}
printf("\nFinal array contents: ");
for (size_t i = 0; i < arr->size; i++) {
printf("%d ", arr->data[i]);
}
printf("\n");
da_destroy(arr);
printf("\nDynamic array destroyed.\n");
}
/* ============================================================
* EXAMPLE 11: Memory Leak Demonstration
* ============================================================ */
void memory_leak_example(void) {
printf("\n=== EXAMPLE 11: Memory Leaks (What NOT to Do) ===\n\n");
printf("MEMORY LEAK SCENARIOS (DON'T DO THESE!):\n\n");
printf("Scenario 1: Forgetting to free\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf(" void leaky_function() {\n");
printf(" int *ptr = malloc(100);\n");
printf(" // ... use ptr ...\n");
printf(" // Oops! Forgot free(ptr);\n");
printf(" } // Memory leaked!\n\n");
printf("Scenario 2: Losing the pointer\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf(" int *ptr = malloc(100);\n");
printf(" ptr = malloc(200); // Lost reference to first block!\n");
printf(" // First 100 bytes are now unreachable\n\n");
printf("Scenario 3: Early return without cleanup\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf(" int *ptr = malloc(100);\n");
printf(" if (some_error) {\n");
printf(" return; // Leak! Didn't free ptr\n");
printf(" }\n");
printf(" free(ptr);\n\n");
printf("CORRECT PATTERN:\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf(" int *ptr = malloc(100);\n");
printf(" if (ptr == NULL) return;\n");
printf(" \n");
printf(" if (some_error) {\n");
printf(" free(ptr); // Clean up before return!\n");
printf(" return;\n");
printf(" }\n");
printf(" \n");
printf(" // ... use ptr ...\n");
printf(" free(ptr);\n");
printf(" ptr = NULL;\n");
}
/* ============================================================
* EXAMPLE 12: Safe Memory Functions
* ============================================================ */
// Safe malloc with error handling
void* safe_malloc(size_t size) {
void *ptr = malloc(size);
if (ptr == NULL) {
fprintf(stderr, "Fatal: malloc(%zu) failed\n", size);
exit(EXIT_FAILURE);
}
return ptr;
}
// Safe calloc with error handling
void* safe_calloc(size_t count, size_t size) {
void *ptr = calloc(count, size);
if (ptr == NULL) {
fprintf(stderr, "Fatal: calloc(%zu, %zu) failed\n", count, size);
exit(EXIT_FAILURE);
}
return ptr;
}
// Safe realloc with error handling
void* safe_realloc(void *ptr, size_t size) {
void *new_ptr = realloc(ptr, size);
if (new_ptr == NULL && size != 0) {
fprintf(stderr, "Fatal: realloc(%zu) failed\n", size);
exit(EXIT_FAILURE);
}
return new_ptr;
}
void example12_safe_functions(void) {
printf("\n=== EXAMPLE 12: Safe Memory Functions ===\n\n");
printf("Using wrapper functions for safety:\n\n");
printf("void* safe_malloc(size_t size) {\n");
printf(" void *ptr = malloc(size);\n");
printf(" if (ptr == NULL) {\n");
printf(" fprintf(stderr, \"Fatal: malloc failed\\n\");\n");
printf(" exit(EXIT_FAILURE);\n");
printf(" }\n");
printf(" return ptr;\n");
printf("}\n\n");
// Demonstrate usage
int *arr = (int *)safe_malloc(5 * sizeof(int));
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
printf("Used safe_malloc to allocate 5 integers: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
}
/* ============================================================
* EXAMPLE 13: Allocating Structures Dynamically
* ============================================================ */
typedef struct {
char *name;
int age;
double salary;
} Employee;
Employee* create_employee(const char *name, int age, double salary) {
Employee *emp = (Employee *)malloc(sizeof(Employee));
if (emp == NULL) return NULL;
emp->name = (char *)malloc(strlen(name) + 1);
if (emp->name == NULL) {
free(emp);
return NULL;
}
strcpy(emp->name, name);
emp->age = age;
emp->salary = salary;
return emp;
}
void destroy_employee(Employee *emp) {
if (emp) {
free(emp->name); // Free inner allocation first
free(emp); // Then free the structure
}
}
void example13_dynamic_structs(void) {
printf("\n=== EXAMPLE 13: Dynamic Structures ===\n\n");
Employee *emp1 = create_employee("Alice Johnson", 30, 75000.0);
Employee *emp2 = create_employee("Bob Smith", 25, 55000.0);
if (emp1 && emp2) {
printf("Employee 1:\n");
printf(" Name: %s\n", emp1->name);
printf(" Age: %d\n", emp1->age);
printf(" Salary: $%.2f\n\n", emp1->salary);
printf("Employee 2:\n");
printf(" Name: %s\n", emp2->name);
printf(" Age: %d\n", emp2->age);
printf(" Salary: $%.2f\n", emp2->salary);
}
destroy_employee(emp1);
destroy_employee(emp2);
printf("\nBoth employees freed (including their names).\n");
}
/* ============================================================
* EXAMPLE 14: Linked List with Dynamic Memory
* ============================================================ */
typedef struct Node {
int data;
struct Node *next;
} Node;
Node* create_node(int data) {
Node *node = (Node *)malloc(sizeof(Node));
if (node) {
node->data = data;
node->next = NULL;
}
return node;
}
void append_node(Node **head, int data) {
Node *new_node = create_node(data);
if (new_node == NULL) return;
if (*head == NULL) {
*head = new_node;
return;
}
Node *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = new_node;
}
void print_list(Node *head) {
Node *current = head;
while (current != NULL) {
printf("%d", current->data);
if (current->next != NULL) {
printf(" -> ");
}
current = current->next;
}
printf(" -> NULL\n");
}
void free_list(Node *head) {
Node *current = head;
while (current != NULL) {
Node *temp = current;
current = current->next;
free(temp);
}
}
void example14_linked_list(void) {
printf("\n=== EXAMPLE 14: Linked List ===\n\n");
Node *head = NULL;
// Build the list
printf("Building linked list...\n");
append_node(&head, 10);
append_node(&head, 20);
append_node(&head, 30);
append_node(&head, 40);
append_node(&head, 50);
printf("List: ");
print_list(head);
// Count nodes
int count = 0;
Node *temp = head;
while (temp) {
count++;
temp = temp->next;
}
printf("Total nodes: %d\n", count);
// Free the list
free_list(head);
head = NULL;
printf("List freed successfully.\n");
}
/* ============================================================
* EXAMPLE 15: Memory Alignment and Size
* ============================================================ */
void example15_alignment(void) {
printf("\n=== EXAMPLE 15: Memory Alignment ===\n\n");
printf("Understanding memory allocation sizes:\n\n");
printf("Type sizeof Typical Alignment\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf("char %zu bytes 1 byte\n", sizeof(char));
printf("short %zu bytes 2 bytes\n", sizeof(short));
printf("int %zu bytes 4 bytes\n", sizeof(int));
printf("long %zu bytes %zu bytes\n", sizeof(long), sizeof(long));
printf("long long %zu bytes 8 bytes\n", sizeof(long long));
printf("float %zu bytes 4 bytes\n", sizeof(float));
printf("double %zu bytes 8 bytes\n", sizeof(double));
printf("pointer (void*) %zu bytes %zu bytes\n", sizeof(void*), sizeof(void*));
printf("\nStructure padding example:\n");
struct Padded {
char c; // 1 byte + 3 padding
int i; // 4 bytes
char d; // 1 byte + 3 padding
};
struct Compact {
int i; // 4 bytes
char c; // 1 byte
char d; // 1 byte + 2 padding
};
printf("struct { char c; int i; char d; } = %zu bytes (with padding)\n",
sizeof(struct Padded));
printf("struct { int i; char c; char d; } = %zu bytes (reordered)\n",
sizeof(struct Compact));
printf("\nTip: Order struct members by size (largest first) to minimize padding.\n");
}
/* ============================================================
* MAIN FUNCTION
* ============================================================ */
int main() {
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf("ā DYNAMIC MEMORY ALLOCATION - EXAMPLES ā\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n\n");
example1_malloc_basics();
example2_malloc_garbage();
example3_calloc();
example4_malloc_vs_calloc();
example5_realloc();
example6_realloc_special();
example7_free_dangling();
example8_patterns();
example9_2d_array();
example10_dynamic_growth();
memory_leak_example();
example12_safe_functions();
example13_dynamic_structs();
example14_linked_list();
example15_alignment();
printf("\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
printf("All examples completed successfully!\n");
printf("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
return 0;
}