109

Edit: I've added the source for the example.

I came across this example:

char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;

/* This is how strcpy works */
printf("destination is originally = '%s'\n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'\n\n", destination);

/* This is how strncpy works */
printf( "destination1 is originally = '%s'\n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'\n", destination1 );

Which produced this output:

destination is originally = 'abcdefg'
After strcpy, destination becomes '123456789'

destination1 is originally = 'abcdefg'
After strncpy, destination1 becomes '12345fg'

Which makes me wonder why anyone would want this effect. It looks like it would be confusing. This program makes me think you could basically copy over someone's name (eg. Tom Brokaw) with Tom Bro763.

What are the advantages of using strncpy() over strcpy()?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Kredns
  • 36,461
  • 52
  • 152
  • 203
  • 96
    I think you meant to ask "Why on earth would anyone use `strcpy` instead of `strncpy`?" – Sam Harwell Aug 11 '09 at 05:24
  • 9
    [My rant on the topic of `strncpy()`](http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html) – Keith Thompson Dec 14 '14 at 05:28
  • 1
    @KeithThompson: From a design standpoint, I think `strncat` is sillier than `strncpy`; how often will one know how much space remains in a buffer following a string of unknown length? If the destination string's length is known, one should find the length of the source (if unknown), clamp that value to the available buffer space, and then use `memcpy` to copy the part that will fit and manually store a zero afterward it. If the destination string's length isn't known, one will usually have to find its length to know how much space is available beyond, in which case the above still applies. – supercat Sep 01 '15 at 20:49
  • 1
    I'm surprised to see @SamHarwell's comment here upvoted so much; it seems to completely miss the point of OP's completely valid question, which is that `strncpy` has strange behavior beyond what you would expect it to be, which is "a safer version of `strcpy` – xdavidliu Oct 22 '22 at 00:29

10 Answers10

208

The strncpy() function was designed with a very particular problem in mind: manipulating strings stored in the manner of original UNIX directory entries. These used a short fixed-sized array (14 bytes), and a nul-terminator was only used if the filename was shorter than the array.

That's what's behind the two oddities of strncpy():

  • It doesn't put a nul-terminator on the destination if it is completely filled; and
  • It always completely fills the destination, with nuls if necessary.

For a "safer strcpy()", you are better off using strncat() like so:

if (dest_size > 0)
{
    dest[0] = '\0';
    strncat(dest, source, dest_size - 1);
}

That will always nul-terminate the result, and won't copy more than necessary.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
caf
  • 233,326
  • 40
  • 323
  • 462
  • But, of course, strncpy isn't always what you want either: strncpy accepts the maximum number of characters to *add* and *not* the destination buffer size... But that's only a minor thing, so probably won't be an issue unless you're trying to concatenate one string onto another. – David Wolever Aug 11 '09 at 23:59
  • I did not know the reason for it, and it's very relevant to what I'm working on atm. – Matt Joiner Sep 21 '10 at 16:18
  • The strncpy() function is designed to store strings in fixed-length null-padded format. Such a format was used for the original Unix directory entries, but is used in countless other places as well, since it allows a string of 0-N bytes to be stored in N bytes of storage. Even today, many databases use null-padded strings in their fixed-length string fields. The confusion with strncpy() stems from the fact that it converts strings to FLNP format. If what one needs is an FLNP string, that's wonderful. If one needs a null-terminated string, one must provide the termination oneself. – supercat Nov 20 '11 at 23:26
  • I don't understand "accepts the maximum number of characters to add and not the destination buffer size" - it doesn't accept either, it accepts an integer: It touches exactly n characters of the dest, and no more. It examines (and copies) characters from the source until it has copied n, or until it encounters a NUL - it never examines more than n characters from the source. – Spike0xff Oct 05 '15 at 20:12
  • 3
    why do we need to write `dest[0] = '\0';` before strncat call? Would you mind explaining sir? – Soner from The Ottoman Empire Mar 06 '19 at 19:31
  • 5
    @snr: `strncat()` concatenates the source string onto the end of the destination string. We just want to copy the source string to the destination, so we first set the destination to the empty string - that's what `dest[0] = '\0';` does. – caf Mar 06 '19 at 22:36
104

strncpy combats buffer overflow by requiring you to put a length in it. strcpy depends on a trailing \0, which may not always occur.

Secondly, why you chose to only copy 5 characters on 7 character string is beyond me, but it's producing expected behavior. It's only copying over the first n characters, where n is the third argument.

The n functions are all used as defensive coding against buffer overflows. Please use them in lieu of older functions, such as strcpy.

Eric
  • 92,005
  • 12
  • 114
  • 115
  • 53
    See http://www.lysator.liu.se/c/rat/d11.html : `strncpy` was initially introduced into the C library to deal with fixed-length name fields in structures such as directory entries. Such fields are not used in the same way as strings: the trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter names to null assures efficient field-wise comparisons. **`strncpy` is not by origin a "bounded strcpy," and the Committee has preferred to recognize existing practice rather than alter the function to better suit it to such use.** – Sinan Ünür Aug 11 '09 at 06:20
  • 41
    I am not sure why this is getting lots of up votes - strncpy was never intended as a safer alternative to strcpy and in fact isn't any safer as it doesn't zero termninate the string. It also has different functionality in that it pads up the supplied length with NUL chars. As caf says in his reply - it is for overwriting strings in a fixed size array. – Dipstick Aug 11 '09 at 06:25
  • 6
    @chris & Sinan: It's getting upvotes because the question was, "Why would you use strncpy instead of strcpy?" Not, "What is strncpy for?" There's a distinct difference. This answer addresses the former, not the latter. – Eric Aug 11 '09 at 06:29
  • 32
    The fact remains that `strncpy` is **not** a safer version of `strcpy`. – Sinan Ünür Aug 11 '09 at 06:33
  • 7
    @Sinan: I never said it was safer. It's defensive. It forces you to put in a length, ergo making you think about what you're doing. There are better solutions, but the fact remains that people would (and do) use `strncpy` instead of `strcpy` because it's a much more defensive function...which is what I said. – Eric Aug 11 '09 at 06:36
  • 11
    *The n functions are all used as defensive coding against buffer overflows. Please use them in lieu of older functions, such as strcpy.* This is true for `snprintf`, but irrelevant for `strncat` and completely untrue for `strncpy`. How could this answer ever get so many upvotes? It shows how bad the situation is regarding this bogus function. Using it is not defensive: in most situations the programmer does not understand its semantics and creates a potentially non zero terminated string. – chqrlie Feb 05 '16 at 19:16
  • 8
    @Eric You failed to mention the obvious fact that `strncpy` will leave the destination string unterminated (if the source string length is greater than or equal to `n`). Thus, it is the very opposite of defensive, it's just begging for a seg fault. – user3386109 Feb 05 '16 at 21:32
  • @user3386109: On the flip side, strncpy requires that the size of the destination be a byte larger than the maximum length of the contents. If a `char[]` is part of a structure, especially one which is used in outside code, there may be significant benefits to saving that byte. – supercat Apr 15 '17 at 16:45
39

While I know the intent behind strncpy, it is not really a good function. Avoid both. Raymond Chen explains.

Personally, my conclusion is simply to avoid strncpy and all its friends if you are dealing with null-terminated strings. Despite the "str" in the name, these functions do not produce null-terminated strings. They convert a null-terminated string into a raw character buffer. Using them where a null-terminated string is expected as the second buffer is plain wrong. Not only do you fail to get proper null termination if the source is too long, but if the source is short you get unnecessary null padding.

See also Why is strncpy insecure?

spaceghost
  • 485
  • 2
  • 12
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
27

strncpy is NOT safer than strcpy, it just trades one type of bugs with another. In C, when handling C strings, you need to know the size of your buffers, there is no way around it. strncpy was justified for the directory thing mentioned by others, but otherwise, you should never use it:

  • if you know the length of your string and buffer, why using strncpy ? It is a waste of computing power at best (adding useless 0)
  • if you don't know the lengths, then you risk silently truncating your strings, which is not much better than a buffer overflow
David Cournapeau
  • 78,318
  • 8
  • 63
  • 70
  • I think this is a good description for strncpy, so I have voted it up. strncpy has it's own set of troubles. I guess that's the reason that e.g glib has it's own extensions. And yes it's unfortunate that you as programmmer has to be aware of the Size of all the arrays. The decison having 0 terminated char array as string, has cost us all dearly.... – Friedrich Oct 21 '09 at 16:04
  • 2
    Zero-padded strings are a pretty common when storing data in fixed-format files. To be sure, the popularity of things like database engines and XML, along with evolving user expectations, have caused fixed-format files to be less common than they were 20 years ago. Nonetheless, such files are often the most time-efficient means of storing data. Except when there's a huge disparity between the expected and maximum length of a data in a record, it's much faster to read a record as a single chunk that contains some unused data than to read a record divided into multiple chunks. – supercat Nov 20 '11 at 23:39
  • Just took over maintenance of legacy code, which used g_strlcpy(), so does not suffer the padding inefficiencies, but sure enough, the count of bytes transferred was NOT maintained, so the code was silently truncating the result. – user2548100 Jan 28 '14 at 19:37
23

What you're looking for is the function strlcpy() which does terminate always the string with 0 and initializes the buffer. It also is able to detect overflows. Only problem, it's not (really) portable and is present only on some systems (BSD, Solaris). The problem with this function is that it opens another can of worms as can be seen by the discussions on http://en.wikipedia.org/wiki/Strlcpy

My personal opinion is that it is vastly more useful than strncpy() and strcpy(). It has better performance and is a good companion to snprintf(). For platforms which do not have it, it is relatively easy to implement. (for the developement phase of a application I substitute these two function (snprintf() and strlcpy()) with a trapping version which aborts brutally the program on buffer overflows or truncations. This allows to catch quickly the worst offenders. Especially if you work on a codebase from someone else.

EDIT: strlcpy() can be implemented easily:

size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
  size_t len = strlen(src);
  if(dstsize) {
    size_t bl = (len < dstsize-1 ? len : dstsize-1);
    ((char*)memcpy(dst, src, bl))[bl] = 0;
  }
  return len;
}
Patrick Schlüter
  • 11,394
  • 1
  • 43
  • 48
  • 3
    You could write that strlcpy is available on pretty much everything other than Linux and Windows! It is, however, BSD licensed, so you can just drop it into one of your libraries and use it from there. – Michael van der Westhuizen Aug 11 '09 at 08:07
  • You might want to add a test for `dstsize > 0` and do nothing if it is not. – chqrlie Feb 05 '16 at 19:19
  • Yes, you're right. I will add the check as without it a `dstsize` will trigger the `memcpy` of length `len` on the destination buffer and overflowing it. – Patrick Schlüter Feb 08 '16 at 08:05
  • Plus one for promoting good solutions. More people need to know about strlcpy because everyone keeps reinventing it poorly. – rsp Jun 26 '16 at 06:16
  • @MichaelvanderWesthuizen It is available on Linux, just not in glibc. See my answers for more info [**(1)**](http://stackoverflow.com/questions/27330913/strncpy-copying-more-than-the-specified-size/38035456#38035456) [**(2)**](http://stackoverflow.com/questions/2114896/why-are-strlcpy-and-strlcat-considered-insecure/38035494#38035494) [**(3)**](http://stackoverflow.com/questions/10425137/copying-n-chars-with-strncpy-more-efficiently-in-c/38035721#38035721) – rsp Jun 26 '16 at 06:19
  • In your second link, you mention the glibc maintainer controversy concerning `strlcpy()`. To show how out to lunch he is on that story, one of his answers was that `strlcpy()` could be replaced by `*(char*)mempcpy(dst, src, bl) = 0`. If you look at my implementation (and at the bug I had), you can see exactly why his answer is ridiculous. – Patrick Schlüter Jun 27 '16 at 07:00
  • Is there any reason the function should require that the source be zero-terminated, versus simply ignoring everything after dstsize-1 bytes? – supercat Jul 05 '16 at 21:23
  • 1. What you describe is the semantic of `strncpy()` and that was what we wanted to avoid with `strlcpy()` in the first place. 2. by ignoring everything after `dstsize-1` when no `nul` character is found, we cannot find the real size of string and readjust the destination buffer accordingly. The important notion here is that we are working on real C strings here, `strncpy()` despite its name initially was never supposed to work on C strings (it was used for fixed size file names in directory entries). – Patrick Schlüter Jul 06 '16 at 10:00
  • @PatrickSchlüter: `strncpy` is designed to *convert* strings from zero-terminated format into fixed-sized zero-padded format. One could use it to copy fixed-size zero-padded strings, but `memcpy` would generally be more efficient for that. – supercat Jun 11 '18 at 21:40
3

The strncpy() function is the safer one: you have to pass the maximum length the destination buffer can accept. Otherwise it could happen that the source string is not correctly 0 terminated, in which case the strcpy() function could write more characters to destination, corrupting anything which is in the memory after the destination buffer. This is the buffer-overrun problem used in many exploits

Also for POSIX API functions like read() which does not put the terminating 0 in the buffer, but returns the number of bytes read, you will either manually put the 0, or copy it using strncpy().

In your example code, index is actually not an index, but a count - it tells how many characters at most to copy from source to destination. If there is no null byte among the first n bytes of source, the string placed in destination will not be null terminated

CsTamas
  • 4,103
  • 5
  • 31
  • 34
1

strncpy fills the destination up with '\0' for the size of source, eventhough the size of the destination is smaller....

manpage:

If the length of src is less than n, strncpy() pads the remainder of dest with null bytes.

and not only the remainder...also after this until n characters is reached. And thus you get an overflow... (see the man page implementation)

Alexander Vogt
  • 17,879
  • 13
  • 52
  • 68
Jeronimo
  • 19
  • 1
  • 3
    *strncpy fills the destination up with '\0' for the size of source, eventhough the size of the destination is smaller....* I'm afraid this statement is erroneous and confusing: `strncpy` fills the destination up with '\0' for the size argument, if the length of the source is less. The size argument is not the size of the source, not a maximum number of characters to copy from the source, as it is in `strncat`, it is the size of the destination. – chqrlie Feb 05 '16 at 19:21
  • @chqrlie: Exactly. An advantage of `strncpy` over other copy operations is that it guarantees that the entire destination will be written. Since compilers may try to get "creative" when copying structures containing some Indeterminate Values, ensuring that any character arrays within structures get written fully may be the simplest way to prevent "surprises". – supercat Apr 15 '17 at 16:34
  • @supercat: a very small advantage for this specific case... but the destination must be patched after the call to `strncpy` to ensure null termination: `strncpy(dest, src, dest_size)[dest_size - 1] = '\0';` – chqrlie Apr 16 '17 at 20:17
  • @chqrlie: Whether or not a trailing null byte would be required would depend upon what the data is supposed to represent. Using zero-padded rather than zero-terminated data within a structure isn't as common as it used to be, but if e.g. an object-file format uses 8-byte section names, being able to have a `char[8]` within a structure handle things up to 8 characters may be nicer than using a `char[8]` but only being able to handle 7 characters, or having to copy a string into `char[9]` buffer and then `memcpy` it to the destination. – supercat Apr 16 '17 at 20:32
  • @chqrlie: Most code that does things with strings should know how long they might be, and shouldn't blindly run with `char` pointers until they hit a zero. The *only* thing zero-terminated strings are really good for is string literals, and even there a variable-length-encoded prefix would probably be better. For almost everything else, it would be better to have strings either prefixed with a length *or* have a special prefix which would indicate that the `char*` is really something like `struct stringInfo {char header[4]; char *realData; size_t length; size_t size;}`. – supercat Apr 16 '17 at 20:37
  • @supercat: indeed `strncpy()` was invented back in the early '70s for this very purpose, but such structures were never popular in C programs and have become vanishingly uncommon today. If the destination does not need to be null terminated, `strncpy()` might be the right tool for the job, otherwise it is a cumbersome and error prone beast that should be avoided. – chqrlie Apr 16 '17 at 20:41
  • @chqrlie: Rather than talking about whether the destination "needs to be" zero-terminated, I'd consider whether it *can*. If a linker or assembler limited identifiers to e.g. 8 bytes, I'd say that likely as not it would hold them in 8 bytes zero-padded. Nowadays memory is plentiful, and the value of supporting longer names is sufficient to justify the extra memory required to allocate storage for arbitrary-length names separate from the associated symbol table entries, but if one is going to store a string *within* a structure it often makes more sense to use zero padding... – supercat Apr 16 '17 at 20:58
  • ...than to have a byte of storage within the structure that always needs to be initialized to zero. – supercat Apr 16 '17 at 20:59
  • @supercat: I beg to disagree: it does not make more sense! such non zero terminated character arrays are cumbersome to manipulate: most standard C string functions cannot be used with them. You seem to come from a different culture where strings are first class objects, it is not the case in C. You can certainly write a set of functions to handle fixed length strings, but this task is daunting as you would need to wrap all library APIs that expect null terminated C strings... Microsoft took this approach to handle Unicode strings, an abysmal mistake in hindsight. – chqrlie Apr 16 '17 at 21:27
  • @chqrlie: Most of the C standard library functions that manipulate strings are poorly designed and shouldn't be used with anything other than literal-constant source operands (if even then). Literal source operands are a common enough case to justify special efforts to make them efficient, but code which allocates buffers for strings has to know how big they are, and code which writes strings of arbitrary length without knowing the buffer size is apt to be brittle at best. Zero-terminated strings were an okay design for handling the common string-literal case without too much RAM overhead... – supercat Apr 16 '17 at 22:25
  • ...but that's just about the only good thing about them. From a performance standpoint, keeping track of length and using memcpy/memmove is almost always going to be better than using any str* functions, and when the source isn't a string literal it's apt to be safer as well. While there are some libraries which unfortunately expect a pointer to a zero-terminated string with no specified maximum length, I regard that as poor design. Unlike null pointes which are a necessary concept, zero-terminated strings are a kludge which should only be used in very narrow cases, and even there... – supercat Apr 16 '17 at 22:39
  • ...only because C lacks any way of creating any other kind of static const object within an expression. – supercat Apr 16 '17 at 22:40
-1

This may be used in many other scenarios, where you need to copy only a portion of your original string to the destination. Using strncpy() you can copy a limited portion of the original string as opposed by strcpy(). I see the code you have put up comes from publib.boulder.ibm.com.

ARV
  • 332
  • 1
  • 3
  • 5
-2

That depends on our requirement. For windows users

We use strncpy whenever we don't want to copy entire string or we want to copy only n number of characters. But strcpy copies the entire string including terminating null character.

These links will help you more to know about strcpy and strncpy and where we can use.

about strcpy

about strncpy

Prakash
  • 100
  • 1
  • 1
  • 8
-8

the strncpy is a safer version of strcpy as a matter of fact you should never use strcpy because its potential buffer overflow vulnerability which makes you system vulnerable to all sort of attacks

bashmohandes
  • 2,356
  • 1
  • 16
  • 23
  • 6
    See http://www.lysator.liu.se/c/rat/d11.html : The strncpy function strncpy was initially introduced into the C library to deal with fixed-length name fields in structures such as directory entries. Such fields are not used in the same way as strings: the trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter names to null assures efficient field-wise comparisons. strncpy is not by origin a ``bounded strcpy,'' and the Committee has preferred to recognize existing practice rather than alter the function to better suit it to such use. – Sinan Ünür Aug 11 '09 at 06:19