Static array declarations require a compile-time constant for their size, which is often impractical when the required memory depends on runtime input. This limitation can lead to either excessive memory waste or buffer overflows.
The malloc functon alllocates a contiguous block of uninitialized memory from the heap. Its counterpart, free, returns previously allocated memory back to the system:
void *malloc(size_t size);
void free(void *ptr);
malloc may allocate slightly more memory than requested for internal bookkeeping. It returns NULL if allocation fails, so checking the return value is essential. The pointer passed to free must be either NULL or a value previously returned by malloc, calloc, or realloc.
calloc differs from malloc in two key ways: it initializes all allocated bytes to zero, and it takes two arguments—the number of elements and the size of each element:
void *calloc(size_t count, size_t size);
realloc adjusts the size of a previously allocated block:
void *realloc(void *ptr, size_t new_size);
When expanding, the added memory is uninitialized; when shrinking, data at the beginning is preserved. If resizing in place isn’t possible, realloc allocates a new block, copies the original data, and frees the old block. Thus, always assign the return value of realloc to a pointer—never assume the address remains unchanged. If the input pointer is NULL, realloc behaves like malloc.
Example usage:
int *arr = malloc(25 * sizeof(int));
if (arr != NULL) {
int *temp = arr;
for (int i = 0; i < 25; ++i) {
*temp++ = 0;
}
// Alternatively:
for (int i = 0; i < 25; ++i) {
arr[i] = 0;
}
}