How strcpy and strncpy Handle Null Termination in C

In C programming, strcpy and strncpy are standard library functions used to duplicate strings, but they differ fundamentally in how they enforce buffer boundaries and null-character (\0) termination. While strcpy unconditionally appends a null terminator at the expense of buffer overflow protection, strncpy restricts writing to a maximum byte count \(n\), introducing nuances where strings may be left unterminated or padded excessively. Understanding these boundary behaviors is essential for writing safe, bug-free C code.

The Behavior of strcpy

The strcpy function follows a simple contract: it copies characters from a source string (src) into a destination buffer (dest) until it encounters the source's terminating null byte (\0), which it also copies.

char *strcpy(char *dest, const char *src);
  • Termination Guarantee: strcpy always null-terminates the destination string, provided the operation completes.
  • Boundary Handling: It completely ignores the allocated capacity of dest. If src contains more characters than dest can hold, strcpy writes past the end of the destination array. This results in undefined behavior, memory corruption, and severe security vulnerabilities such as buffer overflows.

The Behavior of strncpy

To prevent buffer overruns, strncpy introduces a third parameter, n, which specifies the maximum number of bytes to write to the destination.

char *strncpy(char *dest, const char *src, size_t n);

However, strncpy was originally designed for fixed-width directory entries in early Unix systems rather than general string safety, leading to two distinct termination boundary conditions:

1. Truncation Leaves the Buffer Unterminated

If the length of src is equal to or greater than n, strncpy copies exactly n bytes and halts. It does not append a null terminator. As a result, dest contains a non-terminated character sequence. Passing this sequence to functions that expect standard C strings (such as printf("%s", dest) or strlen(dest)) will cause them to read past the buffer boundary until they encounter an arbitrary \0 in memory.

2. Excessive Zero-Padding

If the length of src is strictly less than n, strncpy writes the string and its null terminator, and then continues writing \0 bytes until the entire count of n bytes has been filled. While this ensures termination, writing zero-bytes across large buffers introduces an unnecessary performance overhead.

Key Differences at a Glance

Feature strcpy strncpy
Bound Checking None Limited to \(n\) bytes
Null Termination Always appends \0 Only appends \0 if strlen(src) < n
Overflow Risk High (unbounded write) Low (bounded by \(n\))
Unterminated String Risk Low (provided memory allows) High (when strlen(src) >= n)
Padding None Pads unused bytes up to \(n\) with \0

Ensuring Safe String Termination

To prevent unterminated buffers when using strncpy, developers must manually enforce termination at the boundary:

strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';

Alternatively, modern C development often avoids both functions in favor of safer alternatives such as snprintf, which guarantees null termination whenever the buffer size is greater than zero:

snprintf(dest, sizeof(dest), "%s", src);