A structured lesson workspace with readable content, hands-on examples, and a clean path to completion.
strcpy copies a string from source to destination. It does not check the destination size. If the source is longer than the destination buffer, you overflow. strncpy was supposed to fix this by taking a size limit. It does limit the copy, but it introduces a different bug: if the source is longer than or equal to the limit, strncpy does not null-terminate the destination. You get a buffer full of characters with no terminator. Every subsequent strlen, printf, or strcat on that buffer reads past the end.
#include <stdio.h>#include <string.h>int main(void) {char dest[32];const char *src = "Hello, C!";strcpy(dest, src);printf("Copied: \"%s\"\n", dest);return 0;}
This works because the source fits. Change src to a 200-character string and you overflow the 32-byte buffer. The compiler does not warn you. The runtime does not stop you. The memory corruption is silent until something reads or writes the overwritten region.
#include <stdio.h>#include <string.h>int main(void) {char dest[8];const char *src = "This is way too long";strncpy(dest, src, sizeof(dest));printf("dest[7] = %d (should be 0 for null terminator)\n", dest[7]);printf("strlen(dest) = %zu\n", strlen(dest));return 0;}
dest[7] is 103, the ASCII code for 'g'. No null terminator. strncpy copied exactly 8 bytes and stopped. strlen then reads past the buffer looking for a zero byte. ASan catches the overread. Without ASan, strlen returns a garbage length and every subsequent operation on dest is corrupted.
#include <stdio.h>#include <string.h>int main(void) {char dest[8];const char *src = "This is way too long";strncpy(dest, src, sizeof(dest) - 1);dest[sizeof(dest) - 1] = '\0';printf("Safe copy: \"%s\"\n", dest);printf("strlen: %zu\n", strlen(dest));return 0;}
Copy at most sizeof(dest) - 1 characters. Then explicitly null-terminate the last byte. This is the canonical strncpy pattern. You will see it in every security-conscious C codebase. It is ugly. It is verbose. It works. In C11 Annex K, strncpy_s handles this automatically, but Annex K is optional and not widely implemented.
For new code, consider snprintf(dest, sizeof(dest), "%s", src) as a strcpy replacement. It always null-terminates. It reports truncation. It handles the size correctly. The old functions persist because of legacy code and inertia. You do not have to perpetuate them. Next: sprintf, the string formatter that writes to a buffer instead of a stream.
Finish the lesson once you have worked through the material. This awards ★ 30 XP.