Implement the Classics
Hand-written my_strlen, my_strcpy/strncpy, my_strcmp, my_memcpy, my_memmove, my_atoi.
Six functions, hand-written instead of called: my_strlen, my_strcpy/my_strncpy, my_strcmp, my_memcpy, my_memmove, my_atoi. Writing them is what actually made the library versions' sharp edges make sense — they're not magic, they're this.
size_t my_strlen(const char *s) {
size_t len = 0;
while (s[len] != '\0') {
len++;
}
return len;
}
int my_strcmp(const char *a, const char *b) {
while (*a && (*a == *b)) {
a++;
b++;
}
return (unsigned char)*a - (unsigned char)*b;
}my_strcmp walking off the end and returning a byte difference is exactly why strcmp returns 0 for equal instead of something more "boolean" — it's genuinely just subtracting the two mismatching bytes, and 0 falls out naturally when nothing mismatches.
memcpy vs memmove
The one real gotcha in this set: memcpy doesn't handle overlapping source and destination correctly — copying forward byte-by-byte into a region that overlaps the source can overwrite bytes before they've been read. memmove checks for overlap and copies in whichever direction (front-to-back or back-to-front) avoids clobbering unread data. Writing both by hand is the only reason I actually remember which one to reach for.
Notes from readers
Comments — via GitHub