string.h: String and Memory Functions in Depth
This chapter is the authoritative reference for <string.h>: signatures, semantics, failure modes, and portability notes for every major string and memory function.
Why This Matters
These functions are the source of a large fraction of memory-safety bugs in C. Knowing the exact contract of strncpy, memcpy, memmove, and the rest is the difference between safe and unsafe code.
Prerequisites
c.core.23— strings and the core character functions.
Core Concept
<string.h> provides two families:
1. String functions (str*): operate on null-terminated strings, scanning for '\0'. 2. Memory functions (mem*): operate on explicit byte counts, no null termination assumed.
Function Reference
strlen
size_t strlen(const char *s);
Returns the number of characters before the first null. UB if s is not null-terminated.
strcpy
char *strcpy(char *dest, const char *src);
Copies src (including null) to dest. UB if dest is too small or buffers overlap.
strncpy
char *strncpy(char *dest, const char *src, size_t n);
Copies up to n characters; pads with zeros if src is shorter. Does not null-terminate if src is at least n characters.
strcat / strncat
char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
Appends src to dest. strcat needs dest large enough and non-overlapping. strncat appends at most n chars and always null-terminates (writes at most n+1 bytes total).
strcmp / strncmp
int strcmp(const char *a, const char *b);
int strncmp(const char *a, const char *b, size_t n);
Lexicographic comparison; returns negative, zero, or positive.
strchr / strrchr
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
First/last occurrence of c (converted to char), or NULL.
strstr
char *strstr(const char *haystack, const char *needle);
First occurrence of needle in haystack, or NULL.
strtok
char *strtok(char *str, const char *delim);
Tokenizes a string, modifying it (replaces delimiters with null). Uses static state, so it is not reentrant and not thread-safe.
strspn / strcspn / strpbrk
size_t strspn(const char *s, const char *accept);
size_t strcspn(const char *s, const char *reject);
char *strpbrk(const char *s, const char *accept);
Span over characters in/not in a set; strpbrk finds the first character from a set.
memcpy
void *memcpy(void *dest, const void *src, size_t n);
Copies exactly n bytes. UB if buffers overlap.
memmove
void *memmove(void *dest, const void *src, size_t n);
Copies exactly n bytes, correctly handling overlap.
memset
void *memset(void *s, int c, size_t n);
Sets n bytes to (unsigned char)c.
memcmp
int memcmp(const void *a, const void *b, size_t n);
Compares n bytes as unsigned char.
memchr
void *memchr(const void *s, int c, size_t n);
Finds first occurrence of (unsigned char)c in n bytes, or NULL.
Examples
memmove for overlapping buffers
#include <string.h>
int main(void)
{
char buf[] = "abcdef";
memmove(buf + 2, buf, 4); /* safe overlap */
/* buf becomes "ababcd" */
return 0;
}
strtok tokenization
#include <string.h>
#include <stdio.h>
int main(void)
{
char s[] = "one,two,three";
for (char *p = strtok(s, ","); p != NULL; p = strtok(NULL, ","))
printf("%s\n", p);
return 0;
}
Expected output: one, two, three (one per line).
Common Mistakes
- Using
strcpy/strcatwith insufficient destination buffers. - Assuming
strncpynull-terminates. - Using
memcpyfor overlapping buffers (usememmove). - Using
strtokin threaded code or on string literals.
Undefined Behavior
- Overlapping buffers with
memcpy,strcpy,strcat.VERIFIED - Passing non-null-terminated strings to
str*functions.VERIFIED - Passing
NULLtostrlen/strcpy/etc.VERIFIED
Portability
- All functions are standard C.
strtok's non-reentrancy is standard; POSIX
provides strtok_r as a reentrant alternative (not ISO C).
Under the Hood
Compilers often replace memcpy/memset/strlen with built-in, optimized versions (vectorized or specialized) when the size is known.
Practical Usage
- Use
memmovefor potentially overlapping copies. - Prefer
snprintfoverstrcpy/strcatfor building strings. - Use
memcpy/memmovefor binary data,str*for text.
Exercises
1. Implement strlen, strcpy, strcmp, memcpy, and memmove from scratch. 2. Demonstrate strncpy non-termination and the correct fix. 3. Show memmove correctly handling overlap and memcpy's UB with overlap. 4. Parse a comma-separated string with strtok.
Deep Challenge
Write a safe string-builder that grows a dynamic buffer and appends formatted content using vsnprintf (or manual formatting), with correct overlap and allocation handling. Explain every memory-safety decision.
Related Concepts
c.core.23— string fundamentals.c.sec.1— buffer overflow.c.mem.memcpy— memory copying.
References
- ISO/IEC 9899:2018 §7.24 (string handling).
Verification
- All signatures and semantics match the standard.
VERIFIED strncpynon-termination,strncattermination.VERIFIEDmemcpyoverlap UB,memmoveoverlap-safe.VERIFIED- No example was executed during generation unless noted. `Execution not
verified.`
Progress
- [ ] Read
- [ ] Understand
- [ ] Complete examples
- [ ] Complete exercises
- [ ] Complete deep challenge
Concept checkboxes
- [ ] strlen/strcpy/strcat/strcmp
- [ ] strncpy/strncat
- [ ] strchr/strrchr/strstr
- [ ] strtok/strspn/strcspn/strpbrk
- [ ] memcpy/memmove/memset/memcmp/memchr
Mastery levels
| Concept | Current level (0–8) | Target level |
|---|---|---|
| c.lib.string | 0 | 6 |