|$ curl https://forge-ai.dev/api/markdown?path=docs/c/stdlib
$cat docs/c-—-standard-library.md
updated Recently·50 min read·published

C — Standard Library

CStandard Librarystdlib.hAdvancedAdvanced🎯Free Tools
Standard Library Overview

The C Standard Library is a collection of headers and function implementations that provide foundational capabilities: I/O, string manipulation, memory management, math, time, character classification, and more. Every conforming C compiler provides these headers, making portable code possible across platforms.

This page covers the major headers in depth with practical examples. Understanding the standard library is essential — not only because you'll use these functions daily, but because many subtle bugs arise from misuse of standard library functions (buffer overflows in string functions, unbounded format strings, locale-dependent behavior).

stdio.h — Formatted Output

The printf family converts values to text according to format specifiers. These are among the most frequently used C functions. Understanding format specifiers, width modifiers, and the difference between stack-based and va_list versions is critical.

stdio_printf.c
C
1#include <stdio.h>
2#include <stdarg.h>
3
4int main(void) {
5 int age = 30;
6 double pi = 3.14159265358979;
7 const char *name = "Alice";
8
9 // printf: basic format specifiers
10 printf("Name: %s, Age: %d, Pi: %.2f\n", name, age, pi);
11
12 // Width and padding
13 printf("[%10s]\n", "right"); // [ right]
14 printf("[%-10s]\n", "left"); // [left ]
15 printf("[%08d]\n", 42); // [00000042]
16 printf("[%#010x]\n", 255); // [0x000000ff]
17
18 // fprintf: write to a FILE stream
19 FILE *log = fopen("output.log", "w");
20 if (log) {
21 fprintf(log, "[%s] Level: %d\n", "INFO", 42);
22 fclose(log);
23 }
24
25 // snprintf: write to a buffer with size limit (SAFE)
26 char buf[64];
27 int written = snprintf(buf, sizeof(buf), "Hello, %s! You are %d.", name, age);
28 printf("Buffer: %s (would need %d chars)\n", buf, written);
29
30 // sprintf: UNSAFE -- no bounds checking (avoid!)
31 // sprintf(buf, "This could overflow: %s", long_string);
32
33 // Return value: number of characters written (excluding null terminator)
34 // Or negative value on error
35 int ret = printf("Return value test\n");
36 printf("printf returned: %d\n", ret);
37
38 return 0;
39}

Common Format Specifiers:

SpecifierTypeExample
%d, %iint (signed decimal)%d → 42
%uunsigned int%u → 42
%ldlong%ld → 100000L
%f, %lfdouble%.2f → 3.14
%schar *%s → hello
%pvoid *%p → 0x7fff5e8
%x, %Xhexadecimal%x → ff
%zusize_t%zu → 64

vprintf for variadic wrappers:

variadic_printf.c
C
1#include <stdio.h>
2#include <stdarg.h>
3
4// Custom logging function using vprintf
5void log_message(const char *level, const char *fmt, ...) {
6 va_list args;
7 fprintf(stderr, "[%s] ", level);
8 va_start(args, fmt);
9 vfprintf(stderr, fmt, args);
10 va_end(args);
11 fprintf(stderr, "\n");
12}
13
14// Custom snprintf-like function using vsnprintf
15int format_string(char *buf, size_t size, const char *fmt, ...) {
16 va_list args;
17 va_start(args, fmt);
18 int result = vsnprintf(buf, size, fmt, args);
19 va_end(args);
20 return result;
21}
22
23int main(void) {
24 log_message("INFO", "User %s logged in from %s", "admin", "192.168.1.1");
25 log_message("ERROR", "Connection failed: %d attempts remaining", 3);
26
27 char msg[128];
28 format_string(msg, sizeof(msg), "Temperature: %.1f degrees", 72.5);
29 printf("%s\n", msg);
30
31 return 0;
32}
stdio.h — Formatted Input

The scanf family reads formatted input. While useful for simple parsing, scanf is notoriously difficult to use correctly due to buffer overflow risks, whitespace handling, and error recovery. fgets + sscanf is often the safer pattern.

stdio_scanf.c
C
1#include <stdio.h>
2#include <string.h>
3
4int main(void) {
5 int age;
6 char name[64];
7 double score;
8
9 // scanf: reads until whitespace, leaves newline in buffer
10 printf("Enter name: ");
11 // %63s limits read to 63 chars + null terminator (prevents overflow)
12 scanf("%63s", name);
13
14 printf("Enter age: ");
15 scanf("%d", &age);
16
17 // DANGER: leaving newline in input buffer can cause problems
18 // Clear the leftover newline
19 int c;
20 while ((c = getchar()) != '\n' && c != EOF);
21
22 printf("Enter score: ");
23 scanf("%lf", &score);
24
25 printf("Name: %s, Age: %d, Score: %.1f\n", name, age, score);
26
27 // fgets + sscanf: the SAFE pattern for line-based input
28 char line[256];
29 printf("Enter data (name age score): ");
30 if (fgets(line, sizeof(line), stdin)) {
31 if (sscanf(line, "%63s %d %lf", name, &age, &score) == 3) {
32 printf("Parsed: %s, %d, %.1f\n", name, age, score);
33 } else {
34 fprintf(stderr, "Invalid input format\n");
35 }
36 }
37
38 // Reading entire lines safely
39 printf("Enter a line: ");
40 if (fgets(line, sizeof(line), stdin)) {
41 // Remove trailing newline
42 line[strcspn(line, "\n")] = '\0';
43 printf("You entered: [%s] (length: %zu)\n",
44 line, strlen(line));
45 }
46
47 return 0;
48}

warning

Never use scanf("%s", buf) without a width limit — it will overflow your buffer. Always use %Ns where N is one less than your buffer size. Better yet, prefer fgets() + sscanf() for line-based input.
stdio.h — File Operations

File I/O in C is built around the FILE stream abstraction. Files are opened with fopen(), which returns a FILE pointer. All subsequent operations use this pointer, and the file is closed with fclose(). Binary I/O uses fread/fwrite; text I/O uses fprintf/fscanf.

stdio_file.c
C
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5// Text file I/O
6void text_file_example(void) {
7 // Write text file
8 FILE *fp = fopen("example.txt", "w");
9 if (!fp) {
10 perror("fopen for write");
11 return;
12 }
13 fprintf(fp, "Line 1: Hello World\n");
14 fprintf(fp, "Line 2: %d + %d = %d\n", 3, 4, 7);
15 fprintf(fp, "Line 3: Pi is %.6f\n", 3.141593);
16 fclose(fp);
17
18 // Read text file line by line
19 fp = fopen("example.txt", "r");
20 if (!fp) {
21 perror("fopen for read");
22 return;
23 }
24 char line[256];
25 int line_num = 0;
26 while (fgets(line, sizeof(line), fp)) {
27 line_num++;
28 printf("Line %d: %s", line_num, line);
29 }
30 fclose(fp);
31}
32
33// Binary file I/O
34void binary_file_example(void) {
35 typedef struct {
36 int id;
37 double value;
38 char name[32];
39 } Record;
40
41 Record records[] = {
42 {1, 3.14, "pi"},
43 {2, 2.718, "e"},
44 {3, 1.414, "sqrt2"}
45 };
46 int count = sizeof(records) / sizeof(records[0]);
47
48 // Write binary file
49 FILE *fp = fopen("records.bin", "wb");
50 if (!fp) return;
51 fwrite(records, sizeof(Record), count, fp);
52 fclose(fp);
53
54 // Read binary file
55 Record loaded[10];
56 fp = fopen("records.bin", "rb");
57 if (!fp) return;
58 size_t read_count = fread(loaded, sizeof(Record), 10, fp);
59 fclose(fp);
60
61 printf("Loaded %zu records\n", read_count);
62 for (size_t i = 0; i < read_count; i++) {
63 printf(" [%d] %s = %.3f\n",
64 loaded[i].id, loaded[i].name, loaded[i].value);
65 }
66}
67
68// File seeking
69void file_seek_example(void) {
70 FILE *fp = fopen("seek_test.bin", "w+b");
71 if (!fp) return;
72
73 // Write 10 integers
74 for (int i = 0; i < 10; i++) {
75 fwrite(&i, sizeof(int), 1, fp);
76 }
77
78 // Seek to position 5 * sizeof(int) and read
79 fseek(fp, 5 * sizeof(int), SEEK_SET);
80 int val;
81 fread(&val, sizeof(int), 1, fp);
82 printf("Value at position 5: %d\n", val);
83
84 // Seek from end
85 fseek(fp, -2 * sizeof(int), SEEK_END);
86 fread(&val, sizeof(int), 1, fp);
87 printf("Second to last: %d\n", val);
88
89 // ftell returns current position
90 printf("Current position: %ld\n", ftell(fp));
91
92 // rewind resets to beginning
93 rewind(fp);
94 printf("After rewind: %ld\n", ftell(fp));
95
96 fclose(fp);
97}
98
99// Character I/O
100void character_io_example(void) {
101 // Write characters one at a time
102 FILE *fp = fopen("chars.txt", "w");
103 if (!fp) return;
104 for (int c = 'A'; c <= 'Z'; c++) {
105 fputc(c, fp);
106 }
107 fclose(fp);
108
109 // Read characters one at a time
110 fp = fopen("chars.txt", "r");
111 if (!fp) return;
112 int c;
113 while ((c = fgetc(fp)) != EOF) {
114 putchar(c);
115 }
116 putchar('\n');
117 fclose(fp);
118}
119
120int main(void) {
121 text_file_example();
122 binary_file_example();
123 file_seek_example();
124 character_io_example();
125 return 0;
126}
ModeDescriptionFile must exist
"r"Read onlyYes
"w"Write (truncate or create)No
"a"Append (create if needed)No
"r+"Read + write (truncate)Yes
"rb", "wb"Binary modeDepends on prefix

info

Always check the return value of fwrite() and fread() against the expected count. Partial reads/writes can occur due to disk full, network issues, or signal interruptions. Use perror() or strerror(errno) to report the error.
stdio.h — Error Handling
stdio_error.c
C
1#include <stdio.h>
2#include <errno.h>
3#include <string.h>
4
5int main(void) {
6 FILE *fp = fopen("/nonexistent/file.txt", "r");
7 if (!fp) {
8 // errno is set by the failed system call
9 fprintf(stderr, "Error %d: %s\n", errno, strerror(errno));
10 perror("fopen failed"); // Prints: "fopen failed: No such file or directory"
11 }
12
13 // errno is a thread-local integer set by system calls on error
14 // Always check errno immediately after the call that failed
15 // before calling another function (which may overwrite errno)
16
17 return 0;
18}
stdlib.h — Memory & Sorting

stdlib.h provides dynamic memory allocation (malloc, calloc, realloc, free), random number generation, sorting with function pointers, and program control. See the Memory Management page for detailed allocation coverage — here we focus on qsort, bsearch, and other utilities.

stdlib_sorting.c
C
1#include <stdio.h>
2#include <stdlib.h>
3#include <time.h>
4#include <string.h>
5
6// qsort comparator: returns <0, 0, or >0
7int compare_ints(const void *a, const void *b) {
8 return (*(int *)a - *(int *)b);
9}
10
11int compare_strings(const void *a, const void *b) {
12 return strcmp(*(const char **)a, *(const char **)b);
13}
14
15// For descending order
16int compare_ints_desc(const void *a, const void *b) {
17 return (*(int *)b - *(int *)a);
18}
19
20// Struct comparator by field
21typedef struct {
22 char name[32];
23 int score;
24} Student;
25
26int compare_students_by_score(const void *a, const void *b) {
27 const Student *sa = (const Student *)a;
28 const Student *sb = (const Student *)b;
29 return sb->score - sa->score; // descending
30}
31
32// bsearch: binary search on sorted array (returns pointer or NULL)
33int find_student(const void *key, const void *array) {
34 const Student *s = (const Student *)key;
35 const Student *arr = (const Student *)array;
36 // Compare by score for binary search on sorted array
37 return s->score - arr->score;
38}
39
40int main(void) {
41 // Random numbers
42 srand((unsigned int)time(NULL));
43 printf("5 random numbers: ");
44 for (int i = 0; i < 5; i++) {
45 printf("%d ", rand() % 100);
46 }
47 printf("\n");
48
49 // qsort: array of integers
50 int nums[] = {42, 17, 93, 8, 55, 21, 76, 34};
51 size_t n = sizeof(nums) / sizeof(nums[0]);
52 qsort(nums, n, sizeof(int), compare_ints);
53 printf("Sorted ascending: ");
54 for (size_t i = 0; i < n; i++) printf("%d ", nums[i]);
55 printf("\n");
56
57 qsort(nums, n, sizeof(int), compare_ints_desc);
58 printf("Sorted descending: ");
59 for (size_t i = 0; i < n; i++) printf("%d ", nums[i]);
60 printf("\n");
61
62 // qsort: array of strings
63 const char *fruits[] = {"banana", "apple", "cherry", "date"};
64 size_t nf = sizeof(fruits) / sizeof(fruits[0]);
65 qsort(fruits, nf, sizeof(char *), compare_strings);
66 printf("Sorted fruits: ");
67 for (size_t i = 0; i < nf; i++) printf("%s ", fruits[i]);
68 printf("\n");
69
70 // bsearch: find element in sorted array
71 int target = 42;
72 int *found = bsearch(&target, nums, n, sizeof(int), compare_ints);
73 if (found) printf("Found %d in sorted array\n", *found);
74
75 // Sorting students by score
76 Student students[] = {
77 {"Alice", 95}, {"Bob", 87}, {"Carol", 92}, {"Dave", 78}
78 };
79 size_t ns = sizeof(students) / sizeof(students[0]);
80 qsort(students, ns, sizeof(Student), compare_students_by_score);
81 printf("Students by score:\n");
82 for (size_t i = 0; i < ns; i++) {
83 printf(" %s: %d\n", students[i].name, students[i].score);
84 }
85
86 // abs, labs, llabs
87 printf("|-42| = %d\n", abs(-42));
88 printf("|-100L| = %ld\n", labs(-100L));
89
90 // String conversion
91 printf("atoi: %d\n", atoi("42"));
92 printf("atof: %.2f\n", atof("3.14"));
93
94 char *endptr;
95 long val = strtol("123abc", &endptr, 10);
96 printf("strtol: %ld (stopped at: '%s')\n", val, endptr);
97
98 // exit, abort, atexit
99 // atexit registers a function to run at exit
100 return 0;
101}

warning

The qsort comparator must handle const void * parameters. Never cast to non-const. Also, avoid subtraction-based comparators for types where overflow is possible (e.g., comparing very large unsigned values). Use explicit if/else instead.
stdlib.h — Environment & Program Control
stdlib_env.c
C
1#include <stdio.h>
2#include <stdlib.h>
3
4int main(void) {
5 // getenv: read environment variable
6 const char *home = getenv("HOME");
7 if (home) {
8 printf("HOME = %s\n", home);
9 }
10
11 const char *path = getenv("PATH");
12 if (path) {
13 printf("PATH length: %zu\n", strlen(path));
14 }
15
16 // system: execute a shell command (use with caution!)
17 int result = system("echo 'Hello from shell'");
18 printf("system returned: %d\n", result);
19
20 // atoi, atof, strtol, strtod: string to number conversion
21 // strtol is the recommended way (provides error detection)
22 char *endptr;
23
24 long i = strtol("42", &endptr, 10);
25 printf("strtol("42"): %ld\n", i);
26
27 double d = strtod("3.14159", &endptr);
28 printf("strtod("3.14159"): %f\n", d);
29
30 // Base 16 (hex)
31 long hex = strtol("0xFF", &endptr, 16);
32 printf("strtol("0xFF", base=16): %ld\n", hex);
33
34 // Error detection with strtol
35 errno = 0;
36 long big = strtol("not_a_number", &endptr, 10);
37 if (errno != 0 || *endptr != '\0') {
38 printf("Conversion failed (errno=%d, leftover='%s')\n",
39 errno, endptr);
40 }
41
42 return 0;
43}
string.h — String Functions

The string.h header provides functions for string manipulation and memory operations. C strings are null-terminated byte arrays — there is no length field, so strlen() must scan the entire string. Many string functions are unsafe by design (no bounds checking), making the bounded variants essential.

string_basic.c
C
1#include <stdio.h>
2#include <string.h>
3
4int main(void) {
5 // strlen: length (excluding null terminator)
6 char hello[] = "Hello, World!";
7 printf("strlen: %zu\n", strlen(hello)); // 13
8
9 // strcpy / strncpy: copy
10 char dst[64];
11 strcpy(dst, hello); // Unsafe: no bounds check
12 printf("strcpy: %s\n", dst);
13
14 // Safe version: strncpy + manual null termination
15 char safe[16];
16 strncpy(safe, hello, sizeof(safe) - 1);
17 safe[sizeof(safe) - 1] = '\0';
18 printf("strncpy: %s\n", safe);
19
20 // strcat / strncat: concatenate
21 char greeting[128] = "Hello";
22 strncat(greeting, ", ", sizeof(greeting) - strlen(greeting) - 1);
23 strncat(greeting, "World!", sizeof(greeting) - strlen(greeting) - 1);
24 printf("strncat: %s\n", greeting);
25
26 // strcmp / strncmp: compare
27 printf("strcmp: %d\n", strcmp("abc", "abd")); // negative
28 printf("strcmp: %d\n", strcmp("abc", "abc")); // 0
29 printf("strncmp: %d\n", strncmp("abcde", "abc", 3)); // 0 (first 3 match)
30
31 // strchr / strrchr: find character
32 const char *path = "/usr/local/bin/program";
33 const char *last_slash = strrchr(path, '/');
34 if (last_slash) printf("Last component: %s\n", last_slash + 1);
35
36 const char *first_slash = strchr(path, '/');
37 if (first_slash) printf("After first slash: %s\n", first_slash + 1);
38
39 // strstr: find substring
40 const char *text = "the quick brown fox jumps over the lazy dog";
41 const char *fox = strstr(text, "fox");
42 if (fox) printf("Found 'fox' at offset: %ld\n", fox - text);
43
44 // strtok: tokenize (modifies the input string!)
45 char input[] = "one,two,three,four";
46 char *token = strtok(input, ",");
47 while (token != NULL) {
48 printf("Token: %s\n", token);
49 token = strtok(NULL, ","); // Continue tokenizing
50 }
51
52 // strspn / strcspn: span of characters
53 const char *s = " hello world ";
54 size_t leading = strspn(s, " \t\n");
55 printf("Leading whitespace: %zu chars\n", leading);
56
57 // strdup: duplicate string (POSIX, commonly available)
58 char *dup = strdup("Allocated copy");
59 if (dup) {
60 printf("strdup: %s\n", dup);
61 free(dup); // Must free!
62 }
63
64 return 0;
65}

warning

strtok() is not thread-safe and modifies the input string. Use strtok_r() (POSIX) or strtok_s() (C11 Annex K) for thread-safe tokenization. For new code, consider implementing your own tokenizer with strcspn/strspn for more control.
string.h — Memory Functions

The memory functions (memset, memcpy, memmove, memcmp) operate on raw bytes regardless of type. They are faster than their string counterparts because they don't search for null terminators and handle arbitrary byte sequences.

string_memory.c
C
1#include <stdio.h>
2#include <string.h>
3
4int main(void) {
5 // memset: fill memory with a byte value
6 int arr[10];
7 memset(arr, 0, sizeof(arr)); // Zero out entire array
8 memset(arr, 0xFF, 5 * sizeof(int)); // Set first 5 ints to 0xFF
9
10 // memcpy: copy non-overlapping memory regions
11 int src[] = {10, 20, 30, 40, 50};
12 int dst[5];
13 memcpy(dst, src, sizeof(src));
14 printf("memcpy: ");
15 for (int i = 0; i < 5; i++) printf("%d ", dst[i]);
16 printf("\n");
17
18 // memmove: copy potentially overlapping memory (SAFE)
19 // memcpy is undefined if src and dst overlap
20 int overlap[] = {1, 2, 3, 4, 5, 6, 7, 8};
21 // Shift elements right by 2: {1, 2, 1, 2, 3, 4, 5, 6}
22 memmove(overlap + 2, overlap, 6 * sizeof(int));
23 printf("memmove: ");
24 for (int i = 0; i < 8; i++) printf("%d ", overlap[i]);
25 printf("\n");
26
27 // memcmp: compare memory byte-by-byte
28 int a[] = {1, 2, 3};
29 int b[] = {1, 2, 4};
30 int result = memcmp(a, b, sizeof(int) * 3);
31 printf("memcmp: %d\n", result); // Negative (3 < 4)
32
33 // Practical: zeroing a struct
34 typedef struct {
35 int id;
36 double values[100];
37 char name[64];
38 } LargeStruct;
39
40 LargeStruct s;
41 memset(&s, 0, sizeof(s)); // Zero everything
42 s.id = 1;
43 printf("Struct id: %d, first value: %f\n", s.id, s.values[0]);
44
45 // Practical: building a buffer
46 char packet[256];
47 memset(packet, 0, sizeof(packet));
48 size_t offset = 0;
49
50 // Header: 4 bytes
51 int header = 0x48656C6C; // "Hell" in ASCII
52 memcpy(packet + offset, &header, sizeof(header));
53 offset += sizeof(header);
54
55 // Payload
56 const char *payload = "Hello from C!";
57 size_t payload_len = strlen(payload);
58 memcpy(packet + offset, payload, payload_len);
59 offset += payload_len;
60
61 printf("Packet: %zu bytes\n", offset);
62
63 return 0;
64}

best practice

Always prefer memmove() over memcpy() when you're not 100% certain the regions don't overlap. Modern compilers optimize memmove() to memcpy() when they can prove no overlap. Use memset() with 0 (not 1!) to zero memory, since 0 is the only value that guarantees a null pointer or zero integer on all platforms.
math.h — Mathematics

The math.h header provides double-precision floating-point math functions. Compile with-lm on Linux to link the math library. C99 and later provide the full set of functions including special values (HUGE_VAL, NAN) and error handling via errno and floating-point exception flags (fenv.h).

math_example.c
C
1#include <stdio.h>
2#include <math.h>
3#include <errno.h>
4#include <fenv.h>
5
6int main(void) {
7 // Trigonometry
8 double angle_deg = 45.0;
9 double angle_rad = angle_deg * M_PI / 180.0;
10 printf("sin(45): %.4f\n", sin(angle_rad));
11 printf("cos(45): %.4f\n", cos(angle_rad));
12 printf("tan(45): %.4f\n", tan(angle_rad));
13
14 // Inverse trig
15 printf("asin(1): %.4f rad = %.1f deg\n",
16 asin(1.0), asin(1.0) * 180.0 / M_PI);
17 printf("atan2(1,1): %.4f\n", atan2(1.0, 1.0));
18
19 // Power and roots
20 printf("pow(2,10): %.0f\n", pow(2.0, 10.0));
21 printf("sqrt(144): %.1f\n", sqrt(144.0));
22 printf("cbrt(27): %.1f\n", cbrt(27.0));
23
24 // Logarithms and exponentials
25 printf("log(e): %.4f\n", log(M_E));
26 printf("log2(1024): %.1f\n", log2(1024.0));
27 printf("log10(1000): %.1f\n", log10(1000.0));
28 printf("exp(1): %.4f\n", exp(1.0));
29
30 // Rounding
31 printf("ceil(2.3): %.1f\n", ceil(2.3)); // 3.0
32 printf("floor(2.8): %.1f\n", floor(2.8)); // 2.0
33 printf("round(2.5): %.1f\n", round(2.5)); // 3.0 (ties to even in C11)
34 printf("trunc(-3.7): %.1f\n", trunc(-3.7)); // -3.0
35
36 // Remainder
37 printf("fmod(7.5, 2.0): %.2f\n", fmod(7.5, 2.0));
38
39 // Min/max
40 printf("fmax(3,7): %.1f\n", fmax(3.0, 7.0));
41 printf("fmin(3,7): %.1f\n", fmin(3.0, 7.0));
42
43 // Absolute value (floating point)
44 printf("fabs(-42.5): %.1f\n", fabs(-42.5));
45
46 // Constants
47 printf("M_PI = %.15f\n", M_PI);
48 printf("HUGE_VAL = %e\n", HUGE_VAL);
49
50 // Error handling with errno
51 feclearexcept(FE_ALL_EXCEPT);
52 errno = 0;
53 double result = sqrt(-1.0); // Domain error
54 if (errno == EDOM) {
55 printf("sqrt(-1): domain error\n");
56 }
57
58 // Overflow
59 feclearexcept(FE_ALL_EXCEPT);
60 errno = 0;
61 result = exp(1000.0);
62 if (errno == ERANGE) {
63 printf("exp(1000): overflow -> HUGE_VAL\n");
64 }
65
66 return 0;
67}
FunctionDescriptionDomain Error
sqrt(x)Square rootx < 0
log(x)Natural logarithmx <= 0
asin(x)Arc sine|x| > 1
pow(x,y)x raised to yx<0, y not integer
exp(x)e^xOverflow → HUGE_VAL
📝

note

Compile with -lm on Linux/GCC to link the math library. On macOS/Clang and MSVC, math functions are linked automatically. C99 provides float versions (sinf, cosf, sqrtf, etc.) and long double versions (sinl, cosl, sqrtl) for different precision needs.
ctype.h — Character Classification

The ctype.h header provides functions to classify and convert individual characters. These functions accept an int argument (the character as unsigned char or EOF) and return non-zero if the condition is true, or zero if false.

ctype_example.c
C
1#include <stdio.h>
2#include <ctype.h>
3#include <string.h>
4
5// Convert string to uppercase
6void to_upper_string(char *str) {
7 for (size_t i = 0; str[i]; i++) {
8 str[i] = (char)toupper((unsigned char)str[i]);
9 }
10}
11
12// Validate that a string contains only digits
13int is_all_digits(const char *str) {
14 for (size_t i = 0; str[i]; i++) {
15 if (!isdigit((unsigned char)str[i])) return 0;
16 }
17 return 1;
18}
19
20// Count character types in a string
21void count_types(const char *str) {
22 int alpha = 0, digit = 0, space = 0, punct = 0, other = 0;
23 for (size_t i = 0; str[i]; i++) {
24 unsigned char c = (unsigned char)str[i];
25 if (isalpha(c)) alpha++;
26 else if (isdigit(c)) digit++;
27 else if (isspace(c)) space++;
28 else if (ispunct(c)) punct++;
29 else other++;
30 }
31 printf("alpha=%d digit=%d space=%d punct=%d other=%d\n",
32 alpha, digit, space, punct, other);
33}
34
35int main(void) {
36 // Classification functions
37 printf("isalpha('A'): %d\n", isalpha('A')); // Non-zero (true)
38 printf("isdigit('5'): %d\n", isdigit('5')); // Non-zero
39 printf("isalnum('z'): %d\n", isalnum('z')); // Non-zero
40 printf("isupper('A'): %d\n", isupper('A')); // Non-zero
41 printf("islower('a'): %d\n", islower('a')); // Non-zero
42 printf("isspace(' '): %d\n", isspace(' ')); // Non-zero
43 printf("isprint('!'): %d\n", isprint('!')); // Non-zero
44 printf("ispunct('@'): %d\n", ispunct('@')); // Non-zero
45
46 // Conversion functions
47 printf("toupper('a'): %c\n", toupper('a')); // A
48 printf("tolower('Z'): %c\n", tolower('Z')); // z
49
50 // Practical examples
51 char text[] = "Hello, World! 123";
52 printf("Original: %s\n", text);
53 to_upper_string(text);
54 printf("Upper: %s\n", text);
55
56 printf("'12345' is all digits: %s\n",
57 is_all_digits("12345") ? "yes" : "no");
58 printf("'12a45' is all digits: %s\n",
59 is_all_digits("12a45") ? "yes" : "no");
60
61 count_types("Hello, World! 123");
62
63 return 0;
64}

info

Always cast char to unsigned char before passing to ctype.h functions. If char is signed (which is implementation-defined), negative values (other than EOF) cause undefined behavior. Use toupper((unsigned char)c) as the safe pattern.
time.h — Date and Time

The time.h header provides functions for getting the current time, measuring elapsed time, and formatting dates. The main types are time_t (calendar time as seconds since epoch), clock_t (processor time), and struct tm (broken-down time components).

time_example.c
C
1#include <stdio.h>
2#include <time.h>
3#include <string.h>
4
5int main(void) {
6 // time(): current calendar time as time_t
7 time_t now = time(NULL);
8 printf("Epoch time: %ld\n", (long)now);
9
10 // ctime(): convert time_t to human-readable string
11 printf("Current time: %s", ctime(&now));
12
13 // localtime(): convert to struct tm (broken-down local time)
14 struct tm *local = localtime(&now);
15 printf("Year: %d, Month: %d, Day: %d\n",
16 local->tm_year + 1900, local->tm_mon + 1, local->tm_mday);
17 printf("Hour: %d, Min: %d, Sec: %d\n",
18 local->tm_hour, local->tm_min, local->tm_sec);
19 printf("Day of week: %d (0=Sunday)\n", local->tm_wday);
20 printf("Day of year: %d\n", local->tm_yday);
21
22 // gmtime(): convert to UTC
23 struct tm *utc = gmtime(&now);
24 printf("UTC: %04d-%02d-%02d %02d:%02d:%02d\n",
25 utc->tm_year + 1900, utc->tm_mon + 1, utc->tm_mday,
26 utc->tm_hour, utc->tm_min, utc->tm_sec);
27
28 // strftime(): format time into a string (SAFE, bounded)
29 char buf[128];
30 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z", local);
31 printf("Formatted: %s\n", buf);
32
33 strftime(buf, sizeof(buf), "%A, %B %d, %Y", local);
34 printf("Long date: %s\n", buf);
35
36 // mktime(): convert struct tm back to time_t
37 struct tm target = {0};
38 target.tm_year = 2025 - 1900; // Years since 1900
39 target.tm_mon = 0; // January (0-based)
40 target.tm_mday = 1; // 1st
41 target.tm_hour = 12;
42 time_t target_time = mktime(&target);
43 printf("New Year 2025: %s", ctime(&target_time));
44
45 // difftime(): difference between two time_t values
46 double diff = difftime(now, target_time);
47 printf("Seconds since Jan 1 2025: %.0f\n", diff);
48
49 // clock(): CPU time used by the program
50 clock_t start = clock();
51 // Simulate work
52 volatile long sum = 0;
53 for (long i = 0; i < 10000000L; i++) sum += i;
54 clock_t end = clock();
55 double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
56 printf("Elapsed CPU time: %.6f seconds\n", elapsed);
57 printf("CLOCKS_PER_SEC: %ld\n", (long)CLOCKS_PER_SEC);
58
59 return 0;
60}
📝

note

time_t is typically seconds since January 1, 1970 (Unix epoch). The strftime() format specifiers are similar to printf: %Y (year), %m (month), %d (day),%H:%M:%S (time), %A (weekday name), %B (month name). See the strftime man page for the full list.
stdint.h — Fixed-Width Integers

The stdint.h header (C99) provides integer types with guaranteed widths. Use these when the exact size matters: protocol headers, binary file formats, network packets, or anywhere you need a specific number of bits.

stdint_example.c
C
1#include <stdio.h>
2#include <stdint.h>
3#include <inttypes.h>
4#include <limits.h>
5
6int main(void) {
7 // Fixed-width signed integers
8 int8_t a = -128; // Exactly 1 byte
9 int16_t b = -32768; // Exactly 2 bytes
10 int32_t c = -2147483648; // Exactly 4 bytes
11 int64_t d = -9223372036854775807LL; // Exactly 8 bytes
12
13 printf("int8_t: %d (size: %zu)\n", a, sizeof(a));
14 printf("int16_t: %d (size: %zu)\n", b, sizeof(b));
15 printf("int32_t: %d (size: %zu)\n", c, sizeof(c));
16 printf("int64_t: %lld (size: %zu)\n", (long long)d, sizeof(d));
17
18 // Fixed-width unsigned integers
19 uint8_t ua = 255;
20 uint16_t ub = 65535;
21 uint32_t uc = 4294967295U;
22 uint64_t ud = 18446744073709551615ULL;
23
24 printf("uint8_t: %u (size: %zu)\n", ua, sizeof(ua));
25 printf("uint16_t: %u (size: %zu)\n", ub, sizeof(ub));
26 printf("uint32_t: %u (size: %zu)\n", uc, sizeof(uc));
27 printf("uint64_t: %llu (size: %zu)\n", (unsigned long long)ud, sizeof(ud));
28
29 // Minimum-width and fast types
30 int_least32_t least32 = 42; // At least 32 bits
31 int_fast32_t fast32 = 42; // Fastest type with at least 32 bits
32 intmax_t max_val = 9223372036854775807LL;
33 uintmax_t umax = 18446744073709551615ULL;
34
35 printf("intmax_t size: %zu\n", sizeof(max_val));
36
37 // Limit macros from limits.h and stdint.h
38 printf("INT8_MIN: %d\n", INT8_MIN);
39 printf("INT8_MAX: %d\n", INT8_MAX);
40 printf("UINT8_MAX: %u\n", UINT8_MAX);
41 printf("INT16_MIN: %d\n", INT16_MIN);
42 printf("INT16_MAX: %d\n", INT16_MAX);
43 printf("UINT16_MAX: %u\n", UINT16_MAX);
44 printf("INT32_MIN: %d\n", INT32_MIN);
45 printf("INT32_MAX: %d\n", INT32_MAX);
46 printf("UINT32_MAX: %u\n", UINT32_MAX);
47
48 // SIZE_MAX: maximum value of size_t
49 printf("SIZE_MAX: %zu\n", SIZE_MAX);
50
51 // inttypes.h: portable format specifiers for fixed-width types
52 int64_t big = 123456789012345LL;
53 printf("int64_t: %" PRId64 "\n", big);
54 printf("uint64_t: %" PRIu64 "\n", (uint64_t)big);
55 printf("hex: %" PRIX64 "\n", (uint64_t)big);
56
57 return 0;
58}

best practice

Use inttypes.h macros (PRId64, PRIu32, etc.) for portable printf/scanf format specifiers. Using %ld for int64_t is undefined behavior on platforms where long is 32 bits. The macros expand to the correct format string for each platform.
assert.h — Assertions

The assert() macro checks a condition at runtime. If the condition is false, it prints a diagnostic message and calls abort(). Assertions are for catching programming errors — never use them for input validation or expected runtime conditions.

assert_example.c
C
1#include <stdio.h>
2#include <assert.h>
3#include <string.h>
4
5// Precondition checking
6void sort_array(int *arr, size_t n) {
7 assert(arr != NULL); // Precondition: array must exist
8 assert(n <= 1000000); // Precondition: reasonable size
9
10 // Sorting logic...
11 (void)arr;
12 (void)n;
13}
14
15// Invariant checking
16struct Stack {
17 int data[100];
18 int top;
19};
20
21void stack_push(struct Stack *s, int value) {
22 assert(s != NULL);
23 assert(s->top < 100); // Invariant: not full
24 s->data[s->top++] = value;
25}
26
27int stack_pop(struct Stack *s) {
28 assert(s != NULL);
29 assert(s->top > 0); // Invariant: not empty
30 return s->data[--s->top];
31}
32
33int main(void) {
34 struct Stack s = {.top = 0};
35 stack_push(&s, 42);
36 stack_push(&s, 99);
37 printf("Popped: %d\n", stack_pop(&s));
38
39 int arr[] = {5, 3, 1, 4, 2};
40 sort_array(arr, 5);
41
42 // In debug builds, assertions are enabled
43 // In release builds with NDEBUG, assert() does nothing:
44 // gcc -DNDEBUG -O2 -o program program.c
45
46 printf("All assertions passed\n");
47 return 0;
48}

warning

Never put side effects inside assert() — they are removed in release builds when NDEBUG is defined. Bad: assert(validate() == 0)because validate() won't run in release. Instead, separate the side effect: int r = validate(); assert(r == 0);
limits.h & float.h — Numeric Limits

limits.h defines the range of integer types, while float.h defines properties of floating-point types. These headers are essential for writing portable code that works correctly regardless of the platform's data type sizes.

limits_float.c
C
1#include <stdio.h>
2#include <limits.h>
3#include <float.h>
4#include <stdint.h>
5
6int main(void) {
7 // Integer limits (from limits.h)
8 printf("=== Integer Limits ===\n");
9 printf("CHAR_BIT: %d\n", CHAR_BIT);
10 printf("CHAR_MIN: %d\n", CHAR_MIN);
11 printf("CHAR_MAX: %d\n", CHAR_MAX);
12 printf("SCHAR_MIN: %d\n", SCHAR_MIN);
13 printf("SCHAR_MAX: %d\n", SCHAR_MAX);
14 printf("UCHAR_MAX: %u\n", UCHAR_MAX);
15 printf("SHRT_MIN: %d\n", SHRT_MIN);
16 printf("SHRT_MAX: %d\n", SHRT_MAX);
17 printf("USHRT_MAX: %u\n", USHRT_MAX);
18 printf("INT_MIN: %d\n", INT_MIN);
19 printf("INT_MAX: %d\n", INT_MAX);
20 printf("UINT_MAX: %u\n", UINT_MAX);
21 printf("LONG_MIN: %ld\n", LONG_MIN);
22 printf("LONG_MAX: %ld\n", LONG_MAX);
23 printf("ULONG_MAX: %lu\n", ULONG_MAX);
24 printf("LLONG_MIN: %lld\n", LLONG_MIN);
25 printf("LLONG_MAX: %lld\n", LLONG_MAX);
26 printf("ULLONG_MAX: %llu\n", ULLONG_MAX);
27
28 // Platform-specific sizes
29 printf("\n=== Actual Sizes ===\n");
30 printf("sizeof(char): %zu\n", sizeof(char));
31 printf("sizeof(short): %zu\n", sizeof(short));
32 printf("sizeof(int): %zu\n", sizeof(int));
33 printf("sizeof(long): %zu\n", sizeof(long));
34 printf("sizeof(llong): %zu\n", sizeof(long long));
35 printf("sizeof(size_t): %zu\n", sizeof(size_t));
36
37 // Floating-point limits (from float.h)
38 printf("\n=== Float Limits ===\n");
39 printf("FLT_RADIX: %d\n", FLT_RADIX);
40 printf("FLT_MANT_DIG: %d\n", FLT_MANT_DIG);
41 printf("FLT_MIN: %e\n", FLT_MIN);
42 printf("FLT_MAX: %e\n", FLT_MAX);
43 printf("FLT_EPSILON: %e\n", FLT_EPSILON);
44 printf("FLT_DIG: %d\n", FLT_DIG);
45 printf("FLT_MIN_EXP: %d\n", FLT_MIN_EXP);
46 printf("FLT_MAX_EXP: %d\n", FLT_MAX_EXP);
47
48 printf("DBL_MANT_DIG: %d\n", DBL_MANT_DIG);
49 printf("DBL_MIN: %e\n", DBL_MIN);
50 printf("DBL_MAX: %e\n", DBL_MAX);
51 printf("DBL_EPSILON: %e\n", DBL_EPSILON);
52 printf("DBL_DIG: %d\n", DBL_DIG);
53
54 // Practical: epsilon comparison for floating point
55 double a = 1.0 / 3.0;
56 double b = 1.0 / 3.0;
57 if (a == b) {
58 printf("a == b (exact comparison)\n");
59 }
60 // For approximate comparison, use epsilon:
61 double diff = a - b;
62 if (diff < DBL_EPSILON && diff > -DBL_EPSILON) {
63 printf("a ~= b (epsilon comparison)\n");
64 }
65
66 return 0;
67}
📝

note

DBL_EPSILON is the smallest value such that 1.0 + DBL_EPSILON != 1.0. Use it for approximate floating-point comparisons. Never compare floating-point numbers with == for equality — use fabs(a - b) < EPSILON instead. The appropriate epsilon depends on the magnitude of your values (relative vs. absolute comparison).
$Blueprint — Engineering Documentation·Section ID: C-STDLIB·Revision: 1.0