Appendix F — The standard library, entry by entry
This appendix is something to look things up in. Where the body dealt with “why”, this gathers “what and how” in one place. It follows Annex B of C23 (N3220), aiming to list every function, macro and type of every header without omission.
How to read it.
| Column | What is in it |
|---|---|
| Name | The function’s name. Where f/l variants exist they share one cell |
| Form | The declaration as the standard writes it. QChar and QVoid are the standard’s notation (C23) for a return that preserves qualifiers — hand in a const pointer and you get one back |
| Arguments and return | What each parameter is, what comes back, and how failure is reported |
| What it does · ★traps | A one-line summary. ★ marks a trap this book treats in the body |
Table 99.1
Three things to say in advance.
First, the Annex K functions (those ending in _s) are included. They are in the standard but optional, and were never widely implemented — that story is in chapter 78. They are marked ★K here.
Second, an empty “trap” cell is written as “none”. Left blank, it could not be told apart from not yet examined.
Third, this appendix is not a transcription of the standard. The declarations are facts and stand as they are, but the explanations are this book’s own, and whatever could be measured was measured.
<string.h> — strings and memory
Body: chapter 65 (close reading), chapter 42 (what a string is), chapter 43 (safe input).
This header mixes functions that take a size with functions that do not. That division is also the division between accidents.
Working on blocks of memory (mem*)
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
memcpy | void *memcpy(void *restrict s1, const void *restrict s2, size_t n) | s1 destination, s2 source, n bytes. Returns s1 | Moves n bytes. ★ If the regions overlap it is outside the contract — that is what restrict promises. If they may overlap, use memmove |
memmove | void *memmove(void *s1, const void *s2, size_t n) | The same. Returns s1 | Moves correctly even when overlapping. No trap — if in doubt, use this |
memcmp | int memcmp(const void *s1, const void *s2, size_t n) | Two regions and a length. Returns negative, 0 or positive | Compares bytes in order. ★ Do not compare whole structs — padding gets into the value (chapter 47) |
memchr | QVoid *memchr(QVoid *s, int c, size_t n) | c is converted to unsigned char. Null if not found | Searches forward within n bytes. Unlike the string functions it does not stop at a NUL |
memset | void *memset(void *s, int c, size_t n) | c converted to unsigned char. Returns s | Fills n bytes with one value. ★ Not a way to make pointers null — all-bits-zero and the null representation are separate things (chapter 36) |
memset_explicit | void *memset_explicit(void *s, int c, size_t n) | As memset | C23. A wipe the optimizer may not remove — for clearing a password just before freeing |
memccpy | void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n) | Copies up to and including c and returns the address after it; null if c was not met | Arrived in C23 (an old POSIX function). Does “copy up to the delimiter” in one step |
memcpy_s | errno_t memcpy_s(void *restrict s1, rsize_t s1max, const void *restrict s2, rsize_t n) | Also takes the destination size s1max. 0 on success | ★K Annex K. On overflow it zeroes the destination and reports an error. Not widely implemented (chapter 78) |
memmove_s | errno_t memmove_s(void *s1, rsize_t s1max, const void *s2, rsize_t n) | The same | ★K The same story |
memset_s | errno_t memset_s(void *s, rsize_t smax, int c, rsize_t n) | The same | ★K The same story. memset_explicit is C23′s answer |
Table 99.2
Copying and joining (strcpy and strcat families)
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
strcpy | char *strcpy(char *restrict s1, const char *restrict s2) | Returns s1 | Copies through the NUL. ★ It does not know the destination’s size — the classic overflow |
strncpy | char *strncpy(char *restrict s1, const char *restrict s2, size_t n) | n is how many bytes to write, not the destination’s size | ★★ Despite the name it is not a safe function. On an exact fit it writes no NUL; when short it fills the remainder with zeros (slow). Chapter 65 |
strcat | char *strcat(char *restrict s1, const char *restrict s2) | Returns s1 | Appends. ★ It does not know the size, and it finds the end again every time — repeated in a loop it becomes quadratic |
strncat | char *strncat(char *restrict s1, const char *restrict s2, size_t n) | n is at most how many bytes to append; the NUL goes on top of that | ★ So the buffer must hold n + 1 — the arithmetic differs from strncpy |
strdup | char *strdup(const char *s) | Null on failure | Arrived in C23. You must free it — ownership comes to you (chapter 89) |
strndup | char *strndup(const char *s, size_t n) | At most n bytes. Null on failure | C23. Stops at n even if no end is found |
strcpy_s | errno_t strcpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2) | 0 on success | ★K Chapter 78 |
strncpy_s | errno_t strncpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n) | 0 on success | ★K Chapter 78 |
strcat_s | errno_t strcat_s(char *restrict s1, rsize_t s1max, const char *restrict s2) | 0 on success | ★K Chapter 78 |
strncat_s | errno_t strncat_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n) | 0 on success | ★K Chapter 78 |
Table 99.3
Comparing, and length
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
strlen | size_t strlen(const char *s) | Bytes, not counting the NUL | ★ Bytes, not characters (chapters 42, 72). And it is O(n), so it does not belong in a loop condition (chapter 41) |
strcmp | int strcmp(const char *s1, const char *s2) | Negative, 0 or positive | ★ Not “dictionary order” but order by unsigned char value. Human ordering is strcoll |
strncmp | int strncmp(const char *s1, const char *s2, size_t n) | The same | Compares the first n bytes. Used for prefix tests |
strcoll | int strcoll(const char *s1, const char *s2) | The same | Compares in the order the locale prescribes (chapter 69). Slow — for repeated comparison use strxfrm |
strxfrm | size_t strxfrm(char *restrict s1, const char *restrict s2, size_t n) | Returns the length needed (excluding the NUL). If that is n or more, the contents of s1 are unspecified | Freezes a locale comparison into a “key”. Keys can then be compared with strcmp |
strnlen_s | size_t strnlen_s(const char *s, size_t maxsize) | At most maxsize; 0 if s is null | ★K Yet this one is broadly useful — it measures a buffer that may have no end |
Table 99.4
Searching and splitting
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
strchr | QChar *strchr(QChar *s, int c) | Null if not found. If c is '\0' it points at the terminating NUL | Finds one byte, searching forward. ★ In a multibyte encoding it can land inside a character (chapter 72) |
strrchr | QChar *strrchr(QChar *s, int c) | The same | Searches backward. Used to find the last separator in a path — ★ with the same danger |
strstr | QChar *strstr(QChar *s1, const char *s2) | Null if not found; s1 if s2 is empty | Finds a substring. The standard prescribes no algorithm — it may be O(nm) in the worst case |
strspn | size_t strspn(const char *s1, const char *s2) | A length | How long the prefix made only of characters from s2 is. Used for skipping |
strcspn | size_t strcspn(const char *s1, const char *s2) | A length | The reverse — how far until a character from s2 appears |
strpbrk | QChar *strpbrk(QChar *s1, const char *s2) | Null if not found | The first place any character of s2 occurs |
strtok | char *strtok(char *restrict s1, const char *restrict s2) | The string on the first call, null thereafter. Null when there are no more | ★★ It destroys the original (writing NULs over the delimiters), and it hides state inside the function — not reentrant, not thread-safe. Chapter 65 |
strtok_s | char *strtok_s(char *restrict s1, rsize_t *restrict s1max, const char *restrict s2, char **restrict ptr) | Keeps the state outside, in ptr | ★K Moving the state out is the right direction. POSIX’s strtok_r had the same idea |
Table 99.5
Error strings
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
strerror | char *strerror(int errnum) | The string for an error number | ★ May return a static buffer — a later call can overwrite it, and thread safety is not guaranteed (chapter 75) |
strerrorlen_s | size_t strerrorlen_s(errno_t errnum) | The length needed | ★K Pairs with strerror_s |
Table 99.6
| Macro or type | What it is | Note |
|---|---|---|
NULL | The null pointer constant | From C23 there is nullptr (chapters 36, 82) |
size_t | The unsigned type of sizes and counts | Its home is <stddef.h> (chapter 35) |
rsize_t | ★K Annex K’s size type | Bounded by RSIZE_MAX |
errno_t | ★K Annex K’s error type | Effectively int |
Table 99.7
<ctype.h> — the kinds of a single byte
Body: chapter 67 (close reading), chapter 9 (the history of character sets).
All fourteen functions have the same shape — they take an int and return an int. ★ In that one line lies the trap that governs the whole header.
| Common to every function | What it is |
|---|---|
| Argument | A value representable as unsigned char, or EOF. ★ Anything else is outside the contract |
| ★ The commonest accident | Passing a char directly. On a machine where char is signed, a byte of 128 or more becomes negative and leaves the contract. Always isalpha((unsigned char)c) |
| Return | The classifying functions return “nonzero if true”, 0 if false. Do not assume 1 |
| Locale | All but isdigit and isxdigit can be changed by LC_CTYPE (chapter 68) |
Table 99.8
| Name | True for | Note · ★traps |
|---|---|---|
isalnum | A letter or a digit | isalpha or isdigit |
isalpha | A letter | ★ Not “A–Z, a–z” — the locale and the character set decide (chapter 9′s EBCDIC) |
isblank | A word separator — space and horizontal tab | C99. Means “blank within a line” |
iscntrl | A control character | Not drawn on screen |
isdigit | 0–9 | ★ Independent of the locale — the standard fixes these ten |
isgraph | A printing character other than space | isprint minus the space |
islower | A lowercase letter | The locale decides |
isprint | A printing character, space included | |
ispunct | A printing character that is neither letter, digit nor space | |
isspace | Whitespace — space, \\n, \\t, \\v, \\f, \\r | Used for skipping input |
isupper | An uppercase letter | The locale decides |
isxdigit | A hexadecimal digit | ★ Independent of the locale |
tolower | Returns the lowercase if it is an uppercase letter, otherwise the argument | ★ One character to one character. Turkish I and German ß break that assumption (chapter 72) |
toupper | The reverse | ★ The same |
Table 99.9
<stdckdint.h> — arithmetic that answers about overflow
Body: chapter 81 (close reading), chapter 27 (integers are finite), chapter 52 (undefined behaviour).
A header C23 brought in. All three are type-generic macros, not functions — which is why the forms say type1 and type2.
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
ckd_add | bool ckd_add(type1 *result, type2 a, type3 b) | Writes the result into result. Returns true if it overflowed, false otherwise | ★ Mind the direction of the return — true is not “success” but “it overflowed” |
ckd_sub | bool ckd_sub(type1 *result, type2 a, type3 b) | The same | Subtraction. Also catches going below 0 in an unsigned type |
ckd_mul | bool ckd_mul(type1 *result, type2 a, type3 b) | The same | Multiplication. ★ The most useful of the three for allocation arithmetic — overflow in n * sizeof *p is a classic security bug |
Table 99.10
| Common contract | What it says | Note |
|---|---|---|
| Accuracy of the result | If it did not overflow, the mathematically correct value | Not “the wrapped value” |
| When it overflowed | result receives the wrapped value | Not undefined behaviour — the value is settled |
| Operands | Integer types other than bool and the bit-precise integers | char is allowed too |
| Feature test | __STDC_VERSION_STDCKDINT_H__ | Check for it and branch |
Table 99.11