To perform dynamic memory allocation, C provides four main
functions from the <stdlib.h> library. These functions allow you
to manually manage the Heap.
The four methods are:
1. malloc() (Memory Allocation)
2. calloc() (Contiguous/Clear
Allocation)
3. realloc() (Re-allocation)
4. free() (De-allocation)
Let's look at each one in detail.
1. malloc() - Memory Allocation
malloc is the most common and basic method. It
"rents" a block of memory for you.
· Analogy: You ask a storage facility for a 50-square-foot unit. They give you a key. The unit is yours, but it's not cleaned out. It's full of whatever "garbage" the last renter left.
·
Syntax: ptr
= (type*) malloc(total_bytes);
·
What it does: Allocates a single,
contiguous block of memory of the specified total_bytes.
· Return Value:
o On
success, it returns a void* (generic)
pointer to the *first byte* of the allocated block. You must cast
this to your desired pointer type (e.g., (int*)).
o On
failure (if the Heap is full), it returns NULL.
· Key Feature: The allocated memory is uninitialized. It contains garbage values. You must manually set the values yourself.
Example with malloc()
#include <stdio.h>
#include <stdlib.h>
int main() {
int* ptr;
int n = 5;
// Allocate memory for an array of 5 integers
ptr = (int*) malloc(n * sizeof(int));
// ALWAYS check for failure
if (ptr == NULL) {
printf("Memory not allocated!\n");
return 1;
} // Memory is full of garbage, so we must initialize it.
printf("Allocated! Now initializing...\n");
for (int i = 0; i < n; i++) {
ptr[i] = i + 1; // Set values 1, 2, 3, 4, 5
} printf("Data: ");
for (int i = 0; i < n; i++) {
printf("%d ", ptr[i]);
}printf("\n");
// We'll discuss free() in its own section
free(ptr);
return 0;
}2. calloc() - Contiguous Allocation
calloc is the "safer" cousin of malloc, preferred for arrays.
· Analogy: You ask for 5 *brand new, clean* storage units. They give you the keys, and you are guaranteed that every unit is empty (set to zero).
·
Syntax: ptr
= (type*) calloc(num_elements, element_size);
·
What it does: Allocates memory for an
array of num_elements,
where each element has a size of element_size.
·
Return Value: Same as malloc (void* pointer on success, NULL on failure).
·
Key Feature: It has two key
differences from malloc:
1. It takes two arguments (number of items, size of one item) which is cleaner for arrays.
2. It initializes all bytes to zero. This is extremely useful and prevents bugs from garbage values.
Example with calloc()
#include <stdio.h>
#include <stdlib.h>
int main() {
int* ptr;
int n = 5;
// Allocate memory for 5 integers
ptr = (int*) calloc(n, sizeof(int));
// ALWAYS check for failure
if (ptr == NULL) {
printf("Memory not allocated!\n");
return 1;
} // The memory is ALREADY initialized to zero.
printf("Data (guaranteed to be zero): ");
for (int i = 0; i < n; i++) {
printf("%d ", ptr[i]); // Will print 0 0 0 0 0
}printf("\n");
free(ptr);
return 0;
}3. realloc() - Re-allocation
realloc is used to resize a block
of memory that you *already* allocated.
· Analogy: You go back to the manager and say, "My 50-square-foot unit is full. I need a 100-square-foot unit."
·
Syntax: new_ptr
= (type*) realloc(old_ptr, new_total_size);
·
What it does: It changes the size of
the memory block pointed to by old_ptr to new_total_size bytes.
Extra Content:
How realloc Works (The Magic)
This is the most complex function. One of three things will happen:
1. Case 1 (Shrinking): If new_total_size is *smaller*, it just
cuts off the end of your block. It returns the same pointer you
gave it.
2. Case 2 (Growing, Easy): If new_total_size is *larger*, it checks
if there is free space *immediately after* your block. If yes, it just extends
your block and returns the same pointer.
3. Case 3 (Growing, Hard): If there is *no* free space after your block, it finds a brand new, larger block somewhere else on the Heap, copies all your old data to the new block, frees your old block, and returns a DIFFERENT pointer (to the new location).
CRITICAL: The realloc Trap!
Because of Case 3, the pointer *might*
change. And if realloc fails (e.g., no block is big enough), it returns NULL.
NEVER do this:
ptr
= realloc(ptr, new_size); // !! BAD PRACTICE !!
Why? If realloc fails, it returns NULL. You will have just overwritten ptr with NULL, losing the *only pointer* to your
original data. You can no longer use it or free it. This is a massive memory leak.
ALWAYS do this (The Safe Way):
int*
temp_ptr = realloc(ptr, new_size);
if (temp_ptr == NULL) {
// Handle the error, BUT 'ptr' is
still valid!
} else {
// Success! Now it's safe to update
'ptr'
ptr = temp_ptr;
}
4. free() - De-allocation
free is the partner to *all* allocation functions. It
"returns the key" to the storage unit.
· Analogy: You give your key back to the manager, telling them you are done with the unit. The manager can now rent it to someone else.
·
Syntax: free(ptr_to_allocated_memory);
·
What it does: De-allocates the block
of memory pointed to by ptr_to_allocated_memory,
returning it to the Heap.
CRITICAL: Rules for free()
1. Memory Leaks: For
every malloc, calloc, or realloc, you MUST have a matching free(). If you don't, you get
a memory leak.
2. Dangling Pointers: Calling free(ptr) does not change ptr. The ptr variable still holds the address,
but that address is no longer valid. Using it is a *huge* bug.
Good Practice: Always set your pointer to NULL immediately after freeing it. This
prevents you from using it by accident.
3. free(ptr);
ptr = NULL; // Now it's safe!
4. Double Free: Never
call free() on
the same pointer twice. This will corrupt the Heap and crash your program. (Fun
fact: free(NULL) is
perfectly safe and does nothing).
5. Stack Memory: Never
call free() on
a pointer to a stack variable (e.g., int
x; int* p = &x; free(p);). This will also crash your
program.
Summary: malloc vs. calloc
|
Feature |
|
|
|
Arguments |
1 (total bytes) |
2 (num elements, element size) |
|
Initialization |
No. (Contains garbage) |
Yes. (Initialized to all zeros) |
|
Typical Use |
Allocating a single struct, or any time initialization isn't needed. |
Allocating arrays, or when zero-initialization is required for safety. |