Resizing memory (calloc, realloc)

Basic types / Pointers

void printArray(const char *name, const int arr[], size_t count) {
    printf("%s is {", name);
    for (size_t i = 0; i < count; i++) {
        if (i > 0) {
            printf(", ");
        }
        printf("%d", arr[i]);
    }
    printf("}\n");
}

//calloc fills the memory with zeros, malloc leaves garbage;
//calloc also checks that count * size does not overflow
size_t count = 3;
int *numbers = calloc(count, sizeof *numbers);
if (numbers == nullptr) {
    return 1;
}
//numbers is {0, 0, 0}
printArray("numbers", numbers, count);

numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;

//realloc returns nullptr when there is no memory, and the old block stays:
//numbers = realloc(numbers, ...) would lose it, so a temporary pointer
size_t newCount = 5;
int *bigger = realloc(numbers, newCount * sizeof *numbers);
if (bigger == nullptr) {
    free(numbers);
    return 1;
}
//realloc may move the block: only the new pointer is valid
numbers = bigger;

//the old values are kept, the new ones hold garbage
numbers[3] = 4;
numbers[4] = 5;
//numbers is {1, 2, 3, 4, 5}
printArray("numbers", numbers, newCount);

//realloc also shrinks; a size of 0 is undefined in C23, use free
int *smaller = realloc(numbers, 2 * sizeof *numbers);
if (smaller != nullptr) {
    numbers = smaller;
}
//numbers is {1, 2}
printArray("numbers", numbers, 2);

free(numbers);