C Header Files: Complete Guide to stdio.h, stdlib.h, string.h, math.h & More
Every C program begins with #include directives that pull in the standard library
functions you need. Knowing which header provides which function — and the gotchas attached to
each — is one of the most practical skills in C. This guide covers every commonly-used C
standard library header with a full function reference, a code example, and important notes
that beginner tutorials usually skip.
Quick Lookup: Which Header Do I Need?
Use this table to find the right header for any function you want to use:
| I want to… | Function(s) | Include |
|---|---|---|
| Print to the terminal | printf, puts, putchar | <stdio.h> |
| Read from the terminal | scanf, fgets, getchar | <stdio.h> |
| Read/write files | fopen, fclose, fread, fwrite | <stdio.h> |
| Allocate heap memory | malloc, calloc, realloc, free | <stdlib.h> |
| Exit the program | exit, abort, atexit | <stdlib.h> |
| Generate random numbers | rand, srand | <stdlib.h> |
| Convert strings to numbers | atoi, atof, strtol, strtod | <stdlib.h> |
| Get string length | strlen | <string.h> |
| Copy/compare strings | strcpy, strncpy, strcmp, strncmp | <string.h> |
| Find char/substring | strchr, strrchr, strstr | <string.h> |
| Fill/copy memory | memset, memcpy, memmove | <string.h> |
| Square root / power | sqrt, pow, cbrt | <math.h> + -lm |
| Trig functions | sin, cos, tan, asin, acos, atan | <math.h> + -lm |
| Round / ceiling / floor | round, ceil, floor | <math.h> + -lm |
| Get current time | time, clock, difftime | <time.h> |
| Format date/time as string | strftime, localtime, gmtime | <time.h> |
| Test if char is digit/letter | isdigit, isalpha, isspace | <ctype.h> |
| Convert char case | toupper, tolower | <ctype.h> |
| Use bool type | bool, true, false | <stdbool.h> (C99) |
| Fixed-width integers | int32_t, uint8_t, int64_t | <stdint.h> (C99) |
stdio.h provides all functions for reading from and writing to the terminal,
files, and strings. It is the first header included in virtually every C program.
| Function | Purpose | Key note |
|---|---|---|
| printf(fmt, ...) | Formatted output to stdout | Returns number of chars written |
| scanf(fmt, ...) | Formatted input from stdin | Returns items read — always check return value |
| fprintf(stream, fmt, ...) | Formatted output to any FILE | Use for stderr: fprintf(stderr, "error") |
| fscanf(stream, fmt, ...) | Formatted input from any FILE | Same caveats as scanf |
| fopen(path, mode) | Open a file | Returns NULL on failure — always check |
| fclose(fp) | Close a file and flush buffer | Always call after fopen |
| fgets(buf, n, stream) | Read a line (safer than gets) | Never use gets() — it has no bounds |
| fputs(s, stream) | Write a string to a FILE | Does not add a newline |
| fread(buf, size, n, fp) | Binary read from file | Returns items read (0 on error/EOF) |
| fwrite(buf, size, n, fp) | Binary write to file | Returns items written |
| feof(fp) | Check end-of-file | True only after a read fails — not before |
| perror(msg) | Print system error + description | Uses errno — call immediately after failure |
| sprintf(buf, fmt, ...) | Formatted print into a string | Unsafe if buf too small — prefer snprintf |
| snprintf(buf, n, fmt, ...) | Formatted print into string (safe) | Limits output to n-1 chars |
#include <stdio.h>
int main() {
FILE *fp = fopen("data.txt", "w");
if (!fp) { perror("fopen"); return 1; }
fprintf(fp, "Line 1: score = %d\n", 95);
fprintf(fp, "Line 2: name = %s\n", "Alice");
fclose(fp);
printf("File written successfully.\n");
return 0;
}
gets() has no way to limit
how many characters it reads — any input longer than the buffer silently overwrites memory.
It was removed from the C standard in C11. Always use fgets(buf, sizeof(buf), stdin)
instead.
stdlib.h is the second most commonly included header. It covers a wide range
of utilities: dynamic memory allocation, string-to-number conversion, random number generation,
sorting, and program exit.
| Function | Purpose | Key note |
|---|---|---|
| malloc(size) | Allocate bytes on heap | Returns NULL on failure — check before use |
| calloc(n, size) | Allocate and zero-initialize | Safer than malloc for arrays |
| realloc(ptr, size) | Resize heap allocation | Assign to temp — if it fails, original is still valid |
| free(ptr) | Release heap memory | Every malloc must have exactly one free |
| exit(code) | Exit program with code | Flushes stdio, calls atexit handlers |
| abort() | Abnormal program termination | Does NOT flush stdio or call atexit |
| atexit(func) | Register cleanup function | Called at normal exit in reverse order |
| rand() | Pseudo-random int 0..RAND_MAX | Seed with srand(time(NULL)) first |
| srand(seed) | Seed random number generator | Call once at program start |
| atoi(s) | String → int | No error detection — prefer strtol |
| atof(s) | String → double | No error detection — prefer strtod |
| strtol(s, end, base) | String → long (with error detection) | Sets errno on overflow, *end = leftover |
| strtod(s, end) | String → double (with error detection) | Preferred over atof |
| qsort(arr, n, sz, cmp) | Sort array | Provide comparison function pointer |
| bsearch(key, arr, n, sz, cmp) | Binary search sorted array | Returns NULL if not found |
| abs(n) / labs(n) | Absolute value int / long | For double use fabs() from math.h |
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand((unsigned)time(NULL)); // seed once
int *arr = malloc(5 * sizeof(int));
if (!arr) { perror("malloc"); return 1; }
for (int i = 0; i < 5; i++) {
arr[i] = rand() % 100; // 0–99
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
return 0;
}
string.h provides functions for working with C strings (null-terminated
char arrays) and raw memory blocks. C has no built-in string type, so these
functions are essential.
| Function | Purpose | Safety note |
|---|---|---|
| strlen(s) | Length of string (not including \0) | Does not count null terminator |
| strcpy(dst, src) | Copy src into dst | Unsafe if dst too small — use strncpy |
| strncpy(dst, src, n) | Copy up to n chars | Does not guarantee null termination if src ≥ n |
| strcat(dst, src) | Append src to dst | Unsafe if dst too small — use strncat |
| strncat(dst, src, n) | Append up to n chars | Always null-terminates |
| strcmp(s1, s2) | Compare two strings | Returns 0 if equal, <0 or >0 otherwise |
| strncmp(s1, s2, n) | Compare up to n chars | Safer for partial comparison |
| strchr(s, c) | Find first occurrence of char c | Returns NULL if not found |
| strrchr(s, c) | Find last occurrence of char c | Returns NULL if not found |
| strstr(haystack, needle) | Find substring | Returns pointer to match or NULL |
| strtok(s, delim) | Tokenize string | Modifies the string — not thread-safe |
| memset(ptr, val, n) | Fill n bytes with val | Use to zero a struct: memset(&s, 0, sizeof(s)) |
| memcpy(dst, src, n) | Copy n bytes | Undefined for overlapping regions — use memmove |
| memmove(dst, src, n) | Copy n bytes (safe for overlap) | Slower than memcpy but always correct |
| memcmp(s1, s2, n) | Compare n bytes | Like strcmp but for raw bytes |
#include <stdio.h>
#include <string.h>
int main() {
char s1[50] = "Hello";
const char *s2 = "World";
printf("Length of s1: %zu\n", strlen(s1)); // 5
strncat(s1, ", ", sizeof(s1) - strlen(s1) - 1);
strncat(s1, s2, sizeof(s1) - strlen(s1) - 1);
printf("%s\n", s1); // Hello, World
if (strcmp(s1, "Hello, World") == 0) {
printf("Strings are equal\n");
}
char *pos = strstr(s1, "World");
if (pos) printf("Found at index: %td\n", pos - s1);
return 0;
}
math.h provides floating-point mathematics. Remember: including this header
is not enough — you must also link the math library with -lm at the end of
your GCC command.
| Function | Purpose | Return type |
|---|---|---|
| sqrt(x) | Square root | double |
| cbrt(x) | Cube root (C99) | double |
| pow(x, y) | x raised to power y | double |
| fabs(x) | Absolute value of double | double |
| ceil(x) | Round up to nearest integer | double |
| floor(x) | Round down to nearest integer | double |
| round(x) | Round to nearest (C99) | double |
| fmod(x, y) | Floating-point remainder x mod y | double |
| log(x) | Natural logarithm (base e) | double |
| log2(x) | Base-2 logarithm (C99) | double |
| log10(x) | Base-10 logarithm | double |
| exp(x) | e raised to power x | double |
| sin/cos/tan(x) | Trigonometric (radians) | double |
| asin/acos/atan(x) | Inverse trig (returns radians) | double |
| atan2(y, x) | Angle from (0,0) to (x,y) | double |
| hypot(x, y) | sqrt(x²+y²) without overflow | double |
gcc program.c -o program -lm. The -lm
must appear after the source files. Without it you get "undefined reference to
'sqrt'" even though you included math.h.
#include <stdio.h>
#include <math.h>
#define PI 3.14159265358979
int main() {
double r = 5.0;
printf("Area of circle: %.4f\n", PI * pow(r, 2));
printf("Hypotenuse (3,4): %.4f\n", hypot(3.0, 4.0));
printf("log2(1024): %.1f\n", log2(1024.0));
return 0;
}
/* Compile: gcc program.c -o program -lm */
time.h provides functions for getting the current time, measuring elapsed time,
and formatting dates and times as strings.
| Function / Type | Purpose |
|---|---|
| time(NULL) | Current calendar time as time_t (seconds since Unix epoch) |
| clock() | CPU time used by the program as clock_t |
| difftime(t2, t1) | Difference between two time_t values in seconds |
| localtime(tp) | Convert time_t to struct tm in local timezone |
| gmtime(tp) | Convert time_t to struct tm in UTC |
| mktime(tm) | Convert struct tm to time_t |
| strftime(buf, n, fmt, tm) | Format struct tm as string (like sprintf for dates) |
| CLOCKS_PER_SEC | Macro: divide clock() result by this to get seconds |
#include <stdio.h>
#include <time.h>
int main() {
/* Print current date/time */
time_t now = time(NULL);
struct tm *t = localtime(&now);
char buf[64];
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", t);
printf("Now: %s\n", buf);
/* Time a computation */
clock_t start = clock();
long sum = 0;
for (long i = 0; i < 100000000L; i++) sum += i;
clock_t end = clock();
printf("Elapsed: %.3f s\n",
(double)(end - start) / CLOCKS_PER_SEC);
return 0;
}
ctype.h provides functions for testing and converting individual characters.
All functions take an int (the character value, or EOF) and
return an int (non-zero = true, 0 = false for tests).
| Function | Returns true if… |
|---|---|
| isalpha(c) | c is a letter (A–Z or a–z) |
| isdigit(c) | c is a decimal digit (0–9) |
| isalnum(c) | c is a letter or digit |
| isspace(c) | c is whitespace (space, tab, newline, etc.) |
| isupper(c) | c is an uppercase letter |
| islower(c) | c is a lowercase letter |
| ispunct(c) | c is a punctuation character |
| isprint(c) | c is a printable character (including space) |
| iscntrl(c) | c is a control character |
| toupper(c) | Convert c to uppercase (returns int, cast to char) |
| tolower(c) | Convert c to lowercase (returns int, cast to char) |
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main() {
const char *s = "Hello, World! 42";
int letters = 0, digits = 0, spaces = 0;
for (int i = 0; s[i]; i++) {
if (isalpha((unsigned char)s[i])) letters++;
else if (isdigit((unsigned char)s[i])) digits++;
else if (isspace((unsigned char)s[i])) spaces++;
}
printf("Letters: %d Digits: %d Spaces: %d\n",
letters, digits, spaces);
return 0;
}
EOF (-1). Passing a
char directly can produce undefined behavior on platforms where char
is signed and the character has a value > 127 (e.g., accented letters). Always cast:
isalpha((unsigned char)c).
C99 Additions: stdbool.h, stdint.h, inttypes.h
C99 introduced several new headers that fill important gaps in the original standard library.
These are now universally available — always compile with -std=c99 or later to use them.
Adds bool as a type alias for _Bool, and true (1)
and false (0) as constants. Makes boolean intent explicit in code. In C23,
these became built-in keywords — stdbool.h is no longer needed.
#include <stdbool.h>
bool is_even(int n) { return n % 2 == 0; }
int main() {
bool found = false;
for (int i = 1; i <= 10; i++) {
if (is_even(i)) { found = true; break; }
}
return found ? 0 : 1;
}
The size of int and long varies by platform (16, 32, or 64 bits).
stdint.h provides types with guaranteed sizes — essential for embedded systems,
network protocols, and any code that must be portable across hardware.
#include <stdio.h>
#include <stdint.h>
int main() {
uint8_t byte = 255; // always 8-bit unsigned
int32_t val = -2147483648; // always 32-bit signed
uint64_t large = 1000000000000ULL;
printf("%u %d %llu\n", byte, val, large);
return 0;
}
Common fixed-width types: int8_t, uint8_t, int16_t,
uint16_t, int32_t, uint32_t, int64_t,
uint64_t. The uintN_t versions are unsigned.
Common Header Mistakes
<math.h>
only gives the compiler the function declarations. The actual compiled math code lives in
libm, which is not linked by default. Fix: gcc prog.c -o prog -lm
(the flag goes at the end).
gets() was deprecated in C99 and
removed in C11 because it cannot limit input length — it is a buffer overflow waiting to
happen. Always use fgets(buf, sizeof(buf), stdin) instead.
atoi("abc") silently returns
0 with no indication of failure. strtol("abc", &end, 10) lets you detect that
the conversion failed by checking whether end == input_str. In production code,
always prefer strtol, strtoll, or strtod.
#include adds the contents of that header to your translation unit, slightly
increasing compile time and potentially causing name conflicts. Include only what you use.
With -Wunused-include-file (supported by some compilers), you can catch this
automatically.
Frequently Asked Questions
math.h only gives the compiler the function declaration.
The actual implementation lives in libm, which is not linked by default. Add
-lm at the end of your GCC command: gcc prog.c -o prog -lm.
atoi() converts a string to int but has no error detection — if the string
is not a valid number, it silently returns 0. strtol(str, &end, base) is safer:
if the conversion fails, end points to the first unconverted character (equal
to str if nothing was converted), and it sets errno on overflow.
Always prefer strtol in production code.
stdbool.h, C has no boolean type — you use int with the
convention that 0 = false and non-zero = true. stdbool.h (C99) adds the
bool type and true/false constants, making boolean
intent explicit and the code more readable. In C23, bool, true,
and false became built-in keywords — stdbool.h is then optional.
memcpy when source and destination regions do not overlap — it is faster.
Use memmove when regions might overlap (e.g., shifting elements within the same
array) — it handles overlapping correctly. Using memcpy on overlapping regions
is undefined behavior.
stdint.h (C99) provides integer types with guaranteed sizes: int8_t,
int16_t, int32_t, int64_t and their unsigned
counterparts (uint8_t, etc.). Use them when you need an exact integer size —
for network protocols (packets have defined byte widths), file formats, hardware registers,
or any code that must produce identical results on 32-bit and 64-bit systems.