c
examples
examples.c🔧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 */