how to use strncpy correctly?

Viewed 8978

I know strncpy is a safer version of strcpy as said here.

However, when I want to copy from src to dst and dst is not a clean buffer, I get unwanted results, which can be avoided by strcpy:

char *p = "123";
char a[10] = "aaaaaa";

strncpy(a,p,strlen(p));
printf("%s\n", a);   // 123aaa

strcpy(a,p);
printf("%s\n", a);   // 123 <- desired output, as the trailing a's are garbage

In my actual case, I know strlen(src) < sizeof(dst) (at least, if that isn't the case, the program will crash a lot sooner), so I can safely strcpy.

However, if strncpy is what I should use, then must I add after dst[strlen(src)] = '\0' to avoid garbage (or maybe better yet, init the buffer beforehand?)?

3 Answers

The third argument of strncpy is meant to represent the size of the target buffer. And when it fills it up, it doesn't add a null terminating character by design.

If you have sufficient space for the terminator and you insist on strncpy, just pass strlen(p) + 1 so it will not assume it exhausted the target buffer.

Like many already noted by now. This use of strncpy defeats the purpose, and is really no better than than a simple call to strcpy. The only practical use for strncpy, is if you want to overwrite a part of the string in-place (which is the use case you stumbled upon). Though that too is questionable use...

how to use strncpy correctly?

When code needs to copy a string to a destination and tolerates the result being not null character terminated nor fully copied, use the sizeof destination for the size argument:

char a[10];
// strncpy(a,p,strlen(p));
strncpy(a, p, sizeof a);

// printf("%s\n", a);
printf("%.*s\n", (int) sizeof a, a);

When code wants to copy a string and detect insufficient memory problems via strncpy() or needs null character '\0' padding, also use the sizeof destination.

char a[10];
strncpy(a, p, sizeof a);
if (a[sizeof a - 1] != '\0') {
  // insufficient memory
  // Maybe set last last character to the null character 
  a[sizeof a - 1] == '\0';
  // or other more robust handling
  return ERROR_INSUFFICIENT_MEMORY;
}

Otherwise do not use strncpy()


There are more efficient ways to detect insufficient memory than via strncpy() when null character '\0' padding is not needed. strncpy() zero fills the rest, if any, of the un-copied buffer. The below consumes much time zero-filling just to provide a insufficiency check.

char a[1000];
strncpy(a, "abc", sizeof a);
if (a[sizeof a - 1] != '\0') {
  ....

Better alternatives employ strlen(), strlcpy(), memcpy(). @Deduplicator.

See also strncpy or strlcpy in my case.

For a standard C lib one-liner, code could use snprintf() and a line of error detection. A good compiler would be expected to analyse snprintf(a, sizeof a, "%s", p) and emit efficient code.

// Copy with no overflow.
// 'a' is always null character terminated.
int len = snprintf(a, sizeof a, "%s", p);
if (len < 0 || (unsigned) len >= sizeof a) Report_truncated_copy();

strncpy() isn't actually a string-function; instead, it deals with which zero-padded sequences of non-zero characters, which together have a known fixed length. It's for example the right tool to fill in data-structures which are thereafter sent to other programs, to the outside, or persisted, to avoid data-leaks.

Trying to use it outside its very specialized niche leads to hideous contortions, and inefficient code.

There are more appropriate ways to go about it, like strlcpy() and/or manually using strlen() and memcpy().

Related