c

examples

examples.c🔧
/**
 * =============================================================================
 * Calloc and Realloc in C - Examples
 * =============================================================================
 * 
 * This file demonstrates the usage of calloc() and realloc() functions
 * for dynamic memory management in C.
 * 
 * Compilation: gcc -o examples examples.c -Wall -Wextra
 * Run: ./examples
 * 
 * Topics covered:
 * - calloc() for zero-initialized allocation
 * - realloc() for resizing memory
 * - Comparison with malloc()
 * - Safe reallocation patterns
 * - Dynamic array growth strategies
 * - Flexible array members
 * =============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <stdint.h>

/* Function prototypes */
void example_01_basic_calloc(void);
void example_02_calloc_vs_malloc(void);
void example_03_calloc_for_structures(void);
void example_04_basic_realloc(void);
void example_05_safe_realloc_pattern(void);
void example_06_realloc_special_cases(void);
void example_07_shrinking_memory(void);
void example_08_dynamic_array_growth(void);
void example_09_string_builder(void);
void example_10_2d_array_with_calloc(void);
void example_11_frequency_counter(void);
void example_12_flexible_array_member(void);
void example_13_memory_pool_simulation(void);
void example_14_safe_reallocarray(void);
void example_15_complete_dynamic_array(void);

/* Helper function prototypes */
void print_array(const int *arr, size_t size, const char *label);
void print_separator(const char *title);

/**
 * Main function - runs all examples
 */
int main(void) {
    printf("\n");
    printf("╔══════════════════════════════════════════════════════════════════╗\n");
    printf("║           Calloc and Realloc in C - Examples                     ║\n");
    printf("╚══════════════════════════════════════════════════════════════════╝\n\n");

    example_01_basic_calloc();
    example_02_calloc_vs_malloc();
    example_03_calloc_for_structures();
    example_04_basic_realloc();
    example_05_safe_realloc_pattern();
    example_06_realloc_special_cases();
    example_07_shrinking_memory();
    example_08_dynamic_array_growth();
    example_09_string_builder();
    example_10_2d_array_with_calloc();
    example_11_frequency_counter();
    example_12_flexible_array_member();
    example_13_memory_pool_simulation();
    example_14_safe_reallocarray();
    example_15_complete_dynamic_array();

    printf("\n");
    printf("╔══════════════════════════════════════════════════════════════════╗\n");
    printf("║                    All Examples Complete!                        ║\n");
    printf("╚══════════════════════════════════════════════════════════════════╝\n\n");

    return 0;
}

/* ==========================================================================
 * Helper Functions
 * ========================================================================== */

void print_separator(const char *title) {
    printf("\n");
    printf("══════════════════════════════════════════════════════════════════\n");
    printf("  %s\n", title);
    printf("══════════════════════════════════════════════════════════════════\n");
}

void print_array(const int *arr, size_t size, const char *label) {
    printf("%s: [", label);
    for (size_t i = 0; i < size; i++) {
        printf("%d", arr[i]);
        if (i < size - 1) printf(", ");
    }
    printf("]\n");
}

/* ==========================================================================
 * Example 1: Basic calloc Usage
 * ========================================================================== */

void example_01_basic_calloc(void) {
    print_separator("Example 1: Basic calloc Usage");
    
    printf("calloc(num_elements, element_size) allocates AND zero-initializes\n\n");
    
    /* Allocate 10 integers, all initialized to 0 */
    int *numbers = calloc(10, sizeof(int));
    
    if (numbers == NULL) {
        printf("Memory allocation failed!\n");
        return;
    }
    
    printf("Allocated 10 integers with calloc:\n");
    print_array(numbers, 10, "numbers");
    
    /* Modify some values */
    numbers[0] = 10;
    numbers[3] = 30;
    numbers[7] = 70;
    
    printf("\nAfter modification:\n");
    print_array(numbers, 10, "numbers");
    
    /* Demonstrate that unmodified values remain 0 */
    int sum = 0;
    for (int i = 0; i < 10; i++) {
        sum += numbers[i];
    }
    printf("Sum of all elements: %d\n", sum);
    
    free(numbers);
    printf("\nMemory freed successfully.\n");
}

/* ==========================================================================
 * Example 2: calloc vs malloc Comparison
 * ========================================================================== */

void example_02_calloc_vs_malloc(void) {
    print_separator("Example 2: calloc vs malloc Comparison");
    
    printf("Comparing initial values of calloc vs malloc:\n\n");
    
    /* Using malloc - uninitialized memory */
    printf("1. Using malloc (uninitialized):\n");
    int *malloc_arr = malloc(5 * sizeof(int));
    if (malloc_arr) {
        printf("   malloc array values (garbage): ");
        for (int i = 0; i < 5; i++) {
            printf("%d ", malloc_arr[i]);
        }
        printf("\n   (Values are unpredictable!)\n");
        free(malloc_arr);
    }
    
    /* Using calloc - zero initialized */
    printf("\n2. Using calloc (zero-initialized):\n");
    int *calloc_arr = calloc(5, sizeof(int));
    if (calloc_arr) {
        printf("   calloc array values: ");
        for (int i = 0; i < 5; i++) {
            printf("%d ", calloc_arr[i]);
        }
        printf("\n   (Always zeros!)\n");
        free(calloc_arr);
    }
    
    /* malloc with manual initialization */
    printf("\n3. Using malloc + memset (equivalent to calloc):\n");
    int *manual_arr = malloc(5 * sizeof(int));
    if (manual_arr) {
        memset(manual_arr, 0, 5 * sizeof(int));
        printf("   Manually zeroed array: ");
        for (int i = 0; i < 5; i++) {
            printf("%d ", manual_arr[i]);
        }
        printf("\n");
        free(manual_arr);
    }
    
    printf("\n");
    printf("When to use each:\n");
    printf("- malloc: When you'll immediately overwrite all values\n");
    printf("- calloc: When you need guaranteed zero initialization\n");
    printf("- calloc: For counter arrays, flag arrays, lookup tables\n");
}

/* ==========================================================================
 * Example 3: calloc for Structures
 * ========================================================================== */

void example_03_calloc_for_structures(void) {
    print_separator("Example 3: calloc for Structures");
    
    typedef struct {
        char name[50];
        int age;
        double salary;
        int active;
    } Employee;
    
    printf("Allocating array of structures with calloc:\n\n");
    
    /* Allocate 3 Employee structures */
    Employee *employees = calloc(3, sizeof(Employee));
    
    if (employees == NULL) {
        printf("Memory allocation failed!\n");
        return;
    }
    
    /* Show initial values (all zeros/nulls) */
    printf("Initial values (from calloc):\n");
    for (int i = 0; i < 3; i++) {
        printf("Employee %d: name='%s', age=%d, salary=%.2f, active=%d\n",
               i, employees[i].name, employees[i].age, 
               employees[i].salary, employees[i].active);
    }
    
    /* Fill in some data */
    strcpy(employees[0].name, "Alice");
    employees[0].age = 30;
    employees[0].salary = 50000.0;
    employees[0].active = 1;
    
    strcpy(employees[1].name, "Bob");
    employees[1].age = 25;
    employees[1].salary = 45000.0;
    employees[1].active = 1;
    
    /* Leave employees[2] with default values */
    
    printf("\nAfter initialization:\n");
    for (int i = 0; i < 3; i++) {
        printf("Employee %d: name='%s', age=%d, salary=%.2f, active=%d\n",
               i, employees[i].name, employees[i].age, 
               employees[i].salary, employees[i].active);
    }
    
    /* Count active employees */
    int active_count = 0;
    for (int i = 0; i < 3; i++) {
        if (employees[i].active) active_count++;
    }
    printf("\nActive employees: %d\n", active_count);
    
    free(employees);
}

/* ==========================================================================
 * Example 4: Basic realloc Usage
 * ========================================================================== */

void example_04_basic_realloc(void) {
    print_separator("Example 4: Basic realloc Usage");
    
    printf("realloc(ptr, new_size) resizes previously allocated memory\n\n");
    
    /* Initial allocation */
    int *arr = malloc(3 * sizeof(int));
    if (arr == NULL) {
        printf("Initial allocation failed!\n");
        return;
    }
    
    arr[0] = 10;
    arr[1] = 20;
    arr[2] = 30;
    
    printf("Initial array (3 elements):\n");
    print_array(arr, 3, "arr");
    printf("Address: %p\n", (void *)arr);
    
    /* Expand to 6 elements */
    printf("\nExpanding to 6 elements...\n");
    int *temp = realloc(arr, 6 * sizeof(int));
    
    if (temp == NULL) {
        printf("Reallocation failed!\n");
        free(arr);
        return;
    }
    
    arr = temp;
    printf("New address: %p\n", (void *)arr);
    printf("(Address may or may not change)\n");
    
    /* Original data is preserved */
    printf("\nOriginal data preserved:\n");
    print_array(arr, 3, "arr[0..2]");
    
    /* New elements contain garbage - initialize them */
    arr[3] = 40;
    arr[4] = 50;
    arr[5] = 60;
    
    printf("\nAfter adding new elements:\n");
    print_array(arr, 6, "arr");
    
    free(arr);
    printf("\nMemory freed successfully.\n");
}

/* ==========================================================================
 * Example 5: Safe realloc Pattern
 * ========================================================================== */

void example_05_safe_realloc_pattern(void) {
    print_separator("Example 5: Safe realloc Pattern");
    
    printf("DANGER: arr = realloc(arr, size); // Memory leak if fails!\n");
    printf("SAFE:   temp = realloc(arr, size); if(temp) arr = temp;\n\n");
    
    int *arr = malloc(5 * sizeof(int));
    if (arr == NULL) return;
    
    for (int i = 0; i < 5; i++) {
        arr[i] = (i + 1) * 10;
    }
    
    printf("Original array:\n");
    print_array(arr, 5, "arr");
    
    /* Safe realloc pattern */
    size_t new_size = 10;
    int *temp = realloc(arr, new_size * sizeof(int));
    
    if (temp == NULL) {
        printf("Reallocation failed! Original data still safe.\n");
        print_array(arr, 5, "arr");  /* arr is still valid */
        free(arr);
        return;
    }
    
    /* Success - update pointer */
    arr = temp;
    
    /* Initialize new elements */
    for (size_t i = 5; i < new_size; i++) {
        arr[i] = (int)(i + 1) * 10;
    }
    
    printf("\nAfter safe realloc (expanded to 10 elements):\n");
    print_array(arr, 10, "arr");
    
    free(arr);
    printf("\n");
    printf("Pattern:\n");
    printf("  int *temp = realloc(arr, new_size);\n");
    printf("  if (temp == NULL) {\n");
    printf("      // Handle error - arr is still valid!\n");
    printf("      free(arr);\n");
    printf("      return error;\n");
    printf("  }\n");
    printf("  arr = temp;  // Safe to update now\n");
}

/* ==========================================================================
 * Example 6: realloc Special Cases
 * ========================================================================== */

void example_06_realloc_special_cases(void) {
    print_separator("Example 6: realloc Special Cases");
    
    /* Case 1: realloc(NULL, size) == malloc(size) */
    printf("Case 1: realloc(NULL, size) acts like malloc(size)\n");
    int *p1 = realloc(NULL, 5 * sizeof(int));
    if (p1) {
        printf("  Allocated 5 integers starting from NULL\n");
        for (int i = 0; i < 5; i++) p1[i] = i;
        print_array(p1, 5, "  p1");
        free(p1);
    }
    
    /* Case 2: Expanding memory */
    printf("\nCase 2: Expanding allocated memory\n");
    int *p2 = malloc(3 * sizeof(int));
    if (p2) {
        p2[0] = 100; p2[1] = 200; p2[2] = 300;
        printf("  Before: ");
        print_array(p2, 3, "p2");
        
        int *temp = realloc(p2, 5 * sizeof(int));
        if (temp) {
            p2 = temp;
            p2[3] = 400; p2[4] = 500;
            printf("  After:  ");
            print_array(p2, 5, "p2");
        }
        free(p2);
    }
    
    /* Case 3: Shrinking memory */
    printf("\nCase 3: Shrinking allocated memory\n");
    int *p3 = malloc(10 * sizeof(int));
    if (p3) {
        for (int i = 0; i < 10; i++) p3[i] = i * 11;
        printf("  Before: ");
        print_array(p3, 10, "p3");
        
        int *temp = realloc(p3, 5 * sizeof(int));
        if (temp) {
            p3 = temp;
            printf("  After:  ");
            print_array(p3, 5, "p3");
            printf("  (Last 5 elements are gone!)\n");
        }
        free(p3);
    }
    
    /* Case 4: New memory is NOT zero-initialized */
    printf("\nCase 4: New memory from expansion is NOT zero-initialized\n");
    int *p4 = calloc(3, sizeof(int));  /* Start with zeros */
    if (p4) {
        printf("  calloc result: ");
        print_array(p4, 3, "p4");
        
        int *temp = realloc(p4, 6 * sizeof(int));
        if (temp) {
            p4 = temp;
            printf("  After realloc: ");
            for (int i = 0; i < 6; i++) printf("%d ", p4[i]);
            printf("\n  (Elements 3-5 may contain garbage!)\n");
        }
        free(p4);
    }
}

/* ==========================================================================
 * Example 7: Shrinking Memory
 * ========================================================================== */

void example_07_shrinking_memory(void) {
    print_separator("Example 7: Shrinking Memory");
    
    printf("Shrinking with realloc to reduce memory usage:\n\n");
    
    /* Allocate large array */
    size_t initial_size = 100;
    int *arr = malloc(initial_size * sizeof(int));
    if (arr == NULL) return;
    
    /* Fill with values */
    for (size_t i = 0; i < initial_size; i++) {
        arr[i] = (int)(i * i);
    }
    
    printf("Allocated %zu integers\n", initial_size);
    printf("First 10: ");
    for (int i = 0; i < 10; i++) printf("%d ", arr[i]);
    printf("...\n");
    
    /* Only need first 20 elements */
    size_t new_size = 20;
    printf("\nShrinking to %zu elements...\n", new_size);
    
    int *temp = realloc(arr, new_size * sizeof(int));
    if (temp) {
        arr = temp;
        printf("Shrink successful!\n");
        printf("All %zu elements: ", new_size);
        for (size_t i = 0; i < new_size; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
    } else {
        printf("Shrink failed (unusual, but original data still valid)\n");
    }
    
    /* Memory savings calculation */
    size_t saved = (initial_size - new_size) * sizeof(int);
    printf("\nMemory saved: %zu bytes\n", saved);
    
    free(arr);
}

/* ==========================================================================
 * Example 8: Dynamic Array Growth
 * ========================================================================== */

void example_08_dynamic_array_growth(void) {
    print_separator("Example 8: Dynamic Array Growth");
    
    printf("Implementing a growable array with doubling strategy:\n\n");
    
    size_t capacity = 4;
    size_t size = 0;
    int *arr = malloc(capacity * sizeof(int));
    
    if (arr == NULL) return;
    
    printf("Initial capacity: %zu\n", capacity);
    
    /* Add elements, growing as needed */
    int values_to_add[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    int num_values = sizeof(values_to_add) / sizeof(values_to_add[0]);
    
    for (int i = 0; i < num_values; i++) {
        /* Check if we need to grow */
        if (size >= capacity) {
            size_t new_capacity = capacity * 2;
            printf("\nGrowing: %zu -> %zu\n", capacity, new_capacity);
            
            int *temp = realloc(arr, new_capacity * sizeof(int));
            if (temp == NULL) {
                printf("Growth failed!\n");
                break;
            }
            arr = temp;
            capacity = new_capacity;
        }
        
        /* Add element */
        arr[size++] = values_to_add[i];
        printf("Added %d, size=%zu, capacity=%zu\n", 
               values_to_add[i], size, capacity);
    }
    
    printf("\nFinal array:\n");
    print_array(arr, size, "arr");
    printf("Size: %zu, Capacity: %zu\n", size, capacity);
    printf("Memory efficiency: %.1f%%\n", (double)size / capacity * 100);
    
    free(arr);
}

/* ==========================================================================
 * Example 9: String Builder with realloc
 * ========================================================================== */

void example_09_string_builder(void) {
    print_separator("Example 9: String Builder with realloc");
    
    printf("Building a string dynamically:\n\n");
    
    size_t capacity = 16;
    size_t length = 0;
    char *str = malloc(capacity);
    
    if (str == NULL) return;
    str[0] = '\0';
    
    /* Words to concatenate */
    const char *words[] = {
        "Hello", " ", "World", "! ", 
        "This ", "is ", "a ", "dynamically ", 
        "built ", "string."
    };
    int num_words = sizeof(words) / sizeof(words[0]);
    
    for (int i = 0; i < num_words; i++) {
        size_t word_len = strlen(words[i]);
        size_t needed = length + word_len + 1;  /* +1 for null terminator */
        
        /* Grow if needed */
        if (needed > capacity) {
            while (capacity < needed) {
                capacity *= 2;
            }
            printf("Growing capacity to %zu\n", capacity);
            
            char *temp = realloc(str, capacity);
            if (temp == NULL) {
                printf("Realloc failed!\n");
                free(str);
                return;
            }
            str = temp;
        }
        
        /* Append word */
        strcat(str, words[i]);
        length += word_len;
    }
    
    printf("\nFinal string: \"%s\"\n", str);
    printf("Length: %zu, Capacity: %zu\n", length, capacity);
    
    /* Shrink to fit */
    char *temp = realloc(str, length + 1);
    if (temp) {
        str = temp;
        printf("After shrink-to-fit, capacity: %zu\n", length + 1);
    }
    
    free(str);
}

/* ==========================================================================
 * Example 10: 2D Array with calloc
 * ========================================================================== */

void example_10_2d_array_with_calloc(void) {
    print_separator("Example 10: 2D Array with calloc");
    
    printf("Creating a zero-initialized 2D matrix:\n\n");
    
    int rows = 4;
    int cols = 5;
    
    /* Allocate array of row pointers */
    int **matrix = calloc(rows, sizeof(int *));
    if (matrix == NULL) return;
    
    /* Allocate each row */
    for (int i = 0; i < rows; i++) {
        matrix[i] = calloc(cols, sizeof(int));
        if (matrix[i] == NULL) {
            /* Cleanup on failure */
            for (int j = 0; j < i; j++) free(matrix[j]);
            free(matrix);
            return;
        }
    }
    
    /* All values are 0 from calloc */
    printf("Initial matrix (all zeros from calloc):\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%3d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    /* Set diagonal elements */
    for (int i = 0; i < rows && i < cols; i++) {
        matrix[i][i] = i + 1;
    }
    
    printf("\nAfter setting diagonal:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%3d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    /* Free memory */
    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);
    printf("\nMatrix freed successfully.\n");
}

/* ==========================================================================
 * Example 11: Frequency Counter with calloc
 * ========================================================================== */

void example_11_frequency_counter(void) {
    print_separator("Example 11: Frequency Counter with calloc");
    
    printf("Counting character frequencies in a string:\n\n");
    
    const char *text = "hello world programming in c";
    printf("Text: \"%s\"\n\n", text);
    
    /* Use calloc for 256 character counters (ASCII) */
    /* All counters start at 0 automatically! */
    int *freq = calloc(256, sizeof(int));
    if (freq == NULL) return;
    
    /* Count frequencies */
    for (int i = 0; text[i] != '\0'; i++) {
        freq[(unsigned char)text[i]]++;
    }
    
    /* Display non-zero frequencies */
    printf("Character frequencies:\n");
    for (int i = 0; i < 256; i++) {
        if (freq[i] > 0) {
            if (i == ' ') {
                printf("  SPACE: %d\n", freq[i]);
            } else {
                printf("  '%c': %d\n", i, freq[i]);
            }
        }
    }
    
    /* Find most common character (excluding space) */
    int max_freq = 0;
    char max_char = '\0';
    for (int i = 0; i < 256; i++) {
        if (i != ' ' && freq[i] > max_freq) {
            max_freq = freq[i];
            max_char = (char)i;
        }
    }
    
    printf("\nMost common character: '%c' (appears %d times)\n", 
           max_char, max_freq);
    
    free(freq);
}

/* ==========================================================================
 * Example 12: Flexible Array Member
 * ========================================================================== */

/* Structure with flexible array member */
typedef struct {
    size_t length;
    int data[];  /* Flexible array member */
} IntArray;

IntArray *intarray_create(size_t size) {
    IntArray *arr = malloc(sizeof(IntArray) + size * sizeof(int));
    if (arr == NULL) return NULL;
    
    arr->length = size;
    /* Initialize data to 0 */
    memset(arr->data, 0, size * sizeof(int));
    return arr;
}

IntArray *intarray_resize(IntArray *arr, size_t new_size) {
    IntArray *new_arr = realloc(arr, sizeof(IntArray) + new_size * sizeof(int));
    if (new_arr == NULL) return arr;  /* Keep original on failure */
    
    /* Initialize new elements if expanding */
    if (new_size > new_arr->length) {
        memset(new_arr->data + new_arr->length, 0, 
               (new_size - new_arr->length) * sizeof(int));
    }
    new_arr->length = new_size;
    return new_arr;
}

void example_12_flexible_array_member(void) {
    print_separator("Example 12: Flexible Array Member");
    
    printf("Using C99 flexible array member with realloc:\n\n");
    
    /* Create array with 5 elements */
    IntArray *arr = intarray_create(5);
    if (arr == NULL) return;
    
    /* Fill with values */
    for (size_t i = 0; i < arr->length; i++) {
        arr->data[i] = (int)(i + 1) * 10;
    }
    
    printf("Initial (5 elements):\n");
    printf("  Length: %zu\n  Data: ", arr->length);
    for (size_t i = 0; i < arr->length; i++) {
        printf("%d ", arr->data[i]);
    }
    printf("\n");
    
    /* Resize to 10 elements */
    arr = intarray_resize(arr, 10);
    
    printf("\nAfter resize (10 elements):\n");
    printf("  Length: %zu\n  Data: ", arr->length);
    for (size_t i = 0; i < arr->length; i++) {
        printf("%d ", arr->data[i]);
    }
    printf("\n");
    printf("  (New elements initialized to 0)\n");
    
    /* Shrink to 3 elements */
    arr = intarray_resize(arr, 3);
    
    printf("\nAfter shrink (3 elements):\n");
    printf("  Length: %zu\n  Data: ", arr->length);
    for (size_t i = 0; i < arr->length; i++) {
        printf("%d ", arr->data[i]);
    }
    printf("\n");
    
    free(arr);
}

/* ==========================================================================
 * Example 13: Memory Pool Simulation
 * ========================================================================== */

typedef struct {
    char *data;
    size_t used;
    size_t capacity;
} SimplePool;

SimplePool *pool_create(size_t initial_capacity) {
    SimplePool *pool = malloc(sizeof(SimplePool));
    if (pool == NULL) return NULL;
    
    pool->data = calloc(initial_capacity, 1);  /* Zero-initialized */
    if (pool->data == NULL) {
        free(pool);
        return NULL;
    }
    
    pool->used = 0;
    pool->capacity = initial_capacity;
    return pool;
}

void *pool_alloc(SimplePool *pool, size_t size) {
    /* Align to 8 bytes */
    size = (size + 7) & ~(size_t)7;
    
    /* Grow if needed */
    if (pool->used + size > pool->capacity) {
        size_t new_capacity = pool->capacity * 2;
        while (new_capacity < pool->used + size) {
            new_capacity *= 2;
        }
        
        char *new_data = realloc(pool->data, new_capacity);
        if (new_data == NULL) return NULL;
        
        /* Zero new memory */
        memset(new_data + pool->capacity, 0, new_capacity - pool->capacity);
        
        pool->data = new_data;
        pool->capacity = new_capacity;
    }
    
    void *ptr = pool->data + pool->used;
    pool->used += size;
    return ptr;
}

void pool_destroy(SimplePool *pool) {
    if (pool) {
        free(pool->data);
        free(pool);
    }
}

void example_13_memory_pool_simulation(void) {
    print_separator("Example 13: Memory Pool Simulation");
    
    printf("Simple memory pool that grows with realloc:\n\n");
    
    SimplePool *pool = pool_create(64);
    if (pool == NULL) return;
    
    printf("Pool created with capacity: %zu bytes\n", pool->capacity);
    
    /* Allocate some objects */
    int *nums[10];
    for (int i = 0; i < 10; i++) {
        nums[i] = pool_alloc(pool, sizeof(int));
        if (nums[i]) {
            *nums[i] = i * 100;
        }
    }
    
    printf("Allocated 10 integers:\n");
    for (int i = 0; i < 10; i++) {
        printf("  nums[%d] = %d\n", i, *nums[i]);
    }
    
    printf("\nPool stats: used=%zu, capacity=%zu\n", pool->used, pool->capacity);
    
    /* Allocate more to trigger growth */
    printf("\nAllocating 100 more bytes...\n");
    char *buffer = pool_alloc(pool, 100);
    if (buffer) {
        strcpy(buffer, "Hello from the pool!");
        printf("Buffer: \"%s\"\n", buffer);
    }
    
    printf("Pool stats: used=%zu, capacity=%zu\n", pool->used, pool->capacity);
    
    /* Note: Individual deallocations not supported */
    /* Free all at once */
    pool_destroy(pool);
    printf("\nPool destroyed (all memory freed at once).\n");
}

/* ==========================================================================
 * Example 14: Safe reallocarray Implementation
 * ========================================================================== */

void *safe_reallocarray(void *ptr, size_t nmemb, size_t size) {
    /* Check for multiplication overflow */
    if (nmemb != 0 && size > SIZE_MAX / nmemb) {
        errno = ENOMEM;
        return NULL;
    }
    return realloc(ptr, nmemb * size);
}

void example_14_safe_reallocarray(void) {
    print_separator("Example 14: Safe reallocarray Implementation");
    
    printf("reallocarray provides overflow-safe reallocation:\n\n");
    
    /* Normal usage */
    printf("1. Normal allocation (1000 integers):\n");
    int *arr = safe_reallocarray(NULL, 1000, sizeof(int));
    if (arr) {
        printf("   Allocated successfully\n");
        arr[0] = 42;
        arr[999] = 84;
        printf("   arr[0]=%d, arr[999]=%d\n", arr[0], arr[999]);
    }
    
    /* Resize */
    printf("\n2. Resize to 2000 integers:\n");
    int *temp = safe_reallocarray(arr, 2000, sizeof(int));
    if (temp) {
        arr = temp;
        printf("   Resized successfully\n");
        printf("   Original values preserved: arr[0]=%d\n", arr[0]);
    }
    
    free(arr);
    
    /* Overflow detection */
    printf("\n3. Overflow detection:\n");
    printf("   Trying to allocate SIZE_MAX elements...\n");
    void *bad = safe_reallocarray(NULL, SIZE_MAX, sizeof(int));
    if (bad == NULL) {
        printf("   Correctly returned NULL (overflow detected!)\n");
        printf("   errno = %d (ENOMEM)\n", errno);
    }
    
    printf("\n");
    printf("Key benefit: Prevents silent integer overflow in:\n");
    printf("  nmemb * size\n");
    printf("which could lead to allocating too little memory!\n");
}

/* ==========================================================================
 * Example 15: Complete Dynamic Array Implementation
 * ========================================================================== */

typedef struct {
    int *data;
    size_t size;
    size_t capacity;
} DynArray;

DynArray *dynarray_create(void) {
    DynArray *arr = malloc(sizeof(DynArray));
    if (arr == NULL) return NULL;
    
    arr->data = calloc(8, sizeof(int));  /* Start with 8 elements */
    if (arr->data == NULL) {
        free(arr);
        return NULL;
    }
    
    arr->size = 0;
    arr->capacity = 8;
    return arr;
}

int dynarray_push(DynArray *arr, int value) {
    if (arr->size >= arr->capacity) {
        size_t new_capacity = arr->capacity * 2;
        int *temp = realloc(arr->data, new_capacity * sizeof(int));
        if (temp == NULL) return 0;  /* Failed */
        
        arr->data = temp;
        arr->capacity = new_capacity;
    }
    
    arr->data[arr->size++] = value;
    return 1;  /* Success */
}

int dynarray_pop(DynArray *arr, int *value) {
    if (arr->size == 0) return 0;
    
    *value = arr->data[--arr->size];
    
    /* Shrink if less than 25% utilized */
    if (arr->capacity > 8 && arr->size < arr->capacity / 4) {
        size_t new_capacity = arr->capacity / 2;
        int *temp = realloc(arr->data, new_capacity * sizeof(int));
        if (temp) {
            arr->data = temp;
            arr->capacity = new_capacity;
        }
    }
    
    return 1;
}

void dynarray_shrink_to_fit(DynArray *arr) {
    if (arr->size == 0) return;
    
    int *temp = realloc(arr->data, arr->size * sizeof(int));
    if (temp) {
        arr->data = temp;
        arr->capacity = arr->size;
    }
}

void dynarray_destroy(DynArray *arr) {
    if (arr) {
        free(arr->data);
        free(arr);
    }
}

void example_15_complete_dynamic_array(void) {
    print_separator("Example 15: Complete Dynamic Array Implementation");
    
    printf("Full-featured dynamic array with push/pop/shrink:\n\n");
    
    DynArray *arr = dynarray_create();
    if (arr == NULL) return;
    
    printf("Created dynamic array (capacity: %zu)\n", arr->capacity);
    
    /* Push elements */
    printf("\nPushing 15 elements:\n");
    for (int i = 1; i <= 15; i++) {
        if (dynarray_push(arr, i * 10)) {
            if (arr->size == arr->capacity || arr->size <= 8) {
                printf("  Pushed %d (size=%zu, capacity=%zu)\n", 
                       i * 10, arr->size, arr->capacity);
            }
        }
    }
    
    printf("\nArray contents: ");
    for (size_t i = 0; i < arr->size; i++) {
        printf("%d ", arr->data[i]);
    }
    printf("\n");
    
    /* Pop elements */
    printf("\nPopping until shrink:\n");
    int value;
    while (arr->size > 3) {
        size_t old_cap = arr->capacity;
        dynarray_pop(arr, &value);
        if (arr->capacity < old_cap) {
            printf("  Shrunk! (size=%zu, capacity=%zu)\n", 
                   arr->size, arr->capacity);
        }
    }
    
    printf("\nRemaining: ");
    for (size_t i = 0; i < arr->size; i++) {
        printf("%d ", arr->data[i]);
    }
    printf("\n");
    printf("Size: %zu, Capacity: %zu\n", arr->size, arr->capacity);
    
    /* Shrink to fit */
    dynarray_shrink_to_fit(arr);
    printf("\nAfter shrink_to_fit: capacity=%zu\n", arr->capacity);
    
    dynarray_destroy(arr);
    printf("\nArray destroyed.\n");
}

/* End of examples.c */
Examples - C Programming Tutorial | DeepML