<stdlib.h> is the “general utilities” header. It handles dynamic memory (malloc, free), ending your program (exit), turning text into numbers (strtol), random numbers (rand), and sorting arrays (qsort). If you have used stdio.h for I/O, stdlib.h is the natural next step for heap memory and helpers.
01
malloc
Allocate.
02
calloc
Zero fill.
03
free
Release.
04
strtol
Parse int.
05
exit
End program.
06
qsort
Sort array.
Fundamentals
Definition and Usage
Stack arrays have a fixed size decided at compile time. malloc asks the operating system for memory at runtime and returns a void * you cast (in C, assignment to typed pointer works implicitly) to your data type. When finished, free returns that memory.
Beyond memory, stdlib.h offers process control (exit, abort, atexit), conversions (atoi, strtol, strtod), pseudo-random numbers (rand, srand), and algorithms (qsort, bsearch).
💡
Beginner Tip
Every malloc/calloc/realloc needs a matching free. Check for NULL after allocation failure. Prefer strtol over atoi when input might be invalid.
int *arr = malloc(n * sizeof *arr);
if (arr == NULL) {
fprintf(stderr, "Out of memory\n");
exit(EXIT_FAILURE);
}
/* use arr */
free(arr);
arr = NULL;
Headers and linking
#include <stdlib.h> — linked automatically with the C library.
Memory functions use size_t from <stddef.h> (included indirectly).
Compile: gcc program.c -std=c11 -o program.
Cheat Sheet
⚡ Quick Reference
Function
Category
Purpose
malloc
Memory
Allocate bytes
calloc
Memory
Allocate + zero
realloc
Memory
Resize block
free
Memory
Release block
strtol
Convert
String to long
exit
Process
End with status
Array
malloc(n * sizeof *p)
Idiom
Parse
strtol(s, &end, 10)
Base 10
Exit
exit(EXIT_FAILURE)
On error
Dice
rand() % 6 + 1
1–6
Hands-On
Examples Gallery
Compile with gcc file.c -std=c11 -o out. All memory examples check for NULL and call free.
📚 Getting Started
Dynamic memory and conversions from the reference.
Example 1 — malloc and free (Dynamic Array)
From the reference: allocate five integers, fill them, print, then free.
C
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t n = 5;
size_t i;
int *arr = malloc(n * sizeof *arr);
if (arr == NULL) {
fprintf(stderr, "Memory allocation failed\n");
return EXIT_FAILURE;
}
for (i = 0; i < n; i++) {
arr[i] = (int)(i + 1);
}
for (i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
arr = NULL;
return EXIT_SUCCESS;
}
📤 Output:
1 2 3 4 5
How It Works
malloc(n * sizeof *arr) allocates space for n ints. Contents are uninitialized—we assign values before reading. sizeof *arr avoids repeating the type. In C, casting malloc’s result is optional.
Example 2 — calloc (Zero-Initialized Array)
calloc sets every byte to zero—handy for counters or fresh buffers.
C
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t n = 5;
size_t i;
int *counts = calloc(n, sizeof *counts);
if (counts == NULL) {
return EXIT_FAILURE;
}
counts[2] = 10;
counts[4] = 3;
for (i = 0; i < n; i++) {
printf("counts[%zu] = %d\n", i, counts[i]);
}
free(counts);
return EXIT_SUCCESS;
}
calloc(5, sizeof(int)) is equivalent to malloc followed by zeroing memory. Unset slots stay 0 without explicit initialization.
📈 Practical Patterns
Growing buffers, safe parsing, and random numbers.
Example 3 — realloc (Grow an Array)
Start small, then expand when you need more elements.
C
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t capacity = 2;
size_t count = 0;
size_t i;
int *data = malloc(capacity * sizeof *data);
int *tmp;
int values[] = { 10, 20, 30, 40 };
if (data == NULL) {
return EXIT_FAILURE;
}
for (i = 0; i < 4; i++) {
if (count == capacity) {
capacity *= 2;
tmp = realloc(data, capacity * sizeof *data);
if (tmp == NULL) {
free(data);
return EXIT_FAILURE;
}
data = tmp;
}
data[count++] = values[i];
}
for (i = 0; i < count; i++) {
printf("%d ", data[i]);
}
printf("\n");
free(data);
return EXIT_SUCCESS;
}
📤 Output:
10 20 30 40
How It Works
Assign realloc to a temporary pointer. If it fails, the original block is still valid. Doubling capacity is a common growth strategy for dynamic arrays.
Example 4 — strtol (Better Than atoi)
Parse a string to integer and detect invalid input—something atoi cannot do.
C
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void) {
const char *good = "12345";
const char *bad = "12abc";
char *end;
long val;
errno = 0;
val = strtol(good, &end, 10);
if (end == good || *end != '\0') {
printf("'%s' is not a valid integer\n", good);
} else {
printf("Parsed '%s' -> %ld\n", good, val);
}
errno = 0;
val = strtol(bad, &end, 10);
if (end == bad || *end != '\0') {
printf("'%s' is not a fully valid integer (stopped at '%s')\n",
bad, end);
} else {
printf("Parsed '%s' -> %ld\n", bad, val);
}
/* Quick demo: atoi on same good string */
printf("atoi(\"%s\") = %d\n", good, atoi(good));
return EXIT_SUCCESS;
}
📤 Output:
Parsed '12345' -> 12345
'12abc' is not a fully valid integer (stopped at 'abc')
atoi("12345") = 12345
How It Works
strtol sets end to the first unparsed character. If that is not '\0', the whole string was not a valid integer. atoi from the reference works on clean input but hides errors. Use strtod for floating-point strings.
Example 5 — rand and srand (Roll a Die)
Seed the generator once, then produce random values in a range.
C
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
int i;
srand((unsigned)time(NULL));
printf("Rolling a die 5 times:\n");
for (i = 0; i < 5; i++) {
int roll = rand() % 6 + 1;
printf(" Roll %d: %d\n", i + 1, roll);
}
printf("RAND_MAX on this system: %d\n", RAND_MAX);
return EXIT_SUCCESS;
}
📤 Output (varies each run):
Rolling a die 5 times:
Roll 1: 4
Roll 2: 1
Roll 3: 6
Roll 4: 2
Roll 5: 5
RAND_MAX on this system: 32767
How It Works
srand(time(NULL)) seeds from the current time so runs differ. rand() % 6 + 1 yields 1–6. The old reference incorrectly showed rand(void)—the correct call is rand() with no arguments. Not suitable for security—use a crypto library for passwords or keys.
Applications
🚀 Common Use Cases
Dynamic arrays — grow lists when input size is unknown at compile time.
String buffers — build text piece by piece with realloc.
Config parsing — strtol/strtod for numeric settings.
Games and simulations — rand for dice, shuffles, or test data.
Sorting data — qsort on arrays of any element type.
Fatal errors — exit(EXIT_FAILURE) when recovery is impossible.
🧠 How stdlib.h Memory Works
1
Request heap memory
malloc/calloc ask the C runtime for a block.
Allocate
2
Use the pointer
Read and write through the returned address while it is valid.
Lifetime
3
free when done
Return the block so it can be reused; avoid leaks and double-free.
Release
=
💬
Flexible programs
Data structures that grow with user input or file size.
Important
📝 Notes
malloc does not zero memory; reading before writing is undefined behavior.
Multiplying sizes for malloc can overflow—check n > SIZE_MAX / sizeof(T) for large n.
Never free the same pointer twice; never use memory after free.
exit runs atexit handlers and flushes stdio; abort does not guarantee cleanup.
atoi/atof return 0 on failure—indistinguishable from a valid zero.
qsort requires a comparison function; array must be sortable in memory as one block.
Performance
⚡ Optimization
Frequent small malloc/free calls can be slow. Pool allocations, reuse buffers, or over-allocate with realloc in batches when profiling shows heap pressure. calloc costs slightly more than malloc due to zeroing—use malloc when you overwrite every byte anyway. Prefer stack arrays when size is small and known at compile time.
Wrap Up
Conclusion
<stdlib.h> powers dynamic memory and everyday utilities in C. Learn malloc/free first, then calloc, realloc, and safe parsing with strtol. Pair with <stdio.h> for output and <string.h> for text manipulation.
Check every allocation, free every block once, and prefer explicit error handling over blind trust in atoi.
Leak memory on every error path—free before return
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about stdlib.h
Memory, conversions, and utilities.
5
Core concepts
💬01
malloc
Heap bytes.
Memory
📚02
free
Release.
Cleanup
📈03
strtol
Safe parse.
Convert
📄04
realloc
Grow array.
Resize
🌐05
exit
Status code.
Process
❓ Frequently Asked Questions
stdlib.h is the C standard general utilities header. It provides dynamic memory functions (malloc, calloc, realloc, free), process control (exit, abort), string-to-number conversion (atoi, strtol, strtod), random numbers (rand, srand), sorting (qsort), searching (bsearch), and macros like EXIT_SUCCESS and RAND_MAX.
malloc(size) allocates size bytes with uninitialized contents. calloc(count, size) allocates count * size bytes and zeroes every byte. Use calloc when you want a clean slate—for example an array that should start at all zeros.
realloc(ptr, new_size) grows or shrinks a block previously allocated by malloc, calloc, or realloc. Use it when a dynamic array needs more room. If realloc fails it returns NULL and leaves the old block valid—assign to a temporary pointer or handle failure carefully.
atoi converts a string to int but reports no errors: invalid input returns 0 and you cannot tell if the string was "0" or garbage. Prefer strtol or strtod with an endptr to detect parse failures and overflow. atoi is fine only for quick demos with trusted input.
free(ptr) returns memory previously allocated by malloc, calloc, or realloc back to the system. Call free exactly once per allocation. After free, do not use the pointer unless you set it to NULL. Double-free and use-after-free are serious bugs.
rand() returns a pseudo-random integer from 0 to RAND_MAX. srand(seed) seeds the generator so the same seed produces the same sequence. Call srand once at program start—often with time(NULL) for variety. rand is not cryptographically secure.
Did you know?
malloc(0) is implementation-defined—it may return NULL or a unique non-null pointer that must not be dereferenced but can be passed to free. In practice, always treat zero-size allocation as a special case and avoid relying on this behavior.