-1

I know there are a lot of answers on the web which say one is better than the other but I have come to this understanding of strncpy() is better in terms of preventing unnecessary crashes in the system because of the missing '\0'. As many people put it, it is quite defensive.

I have already gone through this link: Why should you use strncpy instead of strcpy?

Let's say:

char dest[5];
char src[7] = "Hello";
strncpy(dest, src, sizeof(dest)-1);

With this implementation (the key being sizeof(dest)-1 which always gives room for the '\0' to be appended), even if the destination has a truncated string, isn't it always safer to use strncpy() instead of strcpy()? In other words, I'm trying to understand when would one want to use strcpy() over strncpy()?

Community
  • 1
  • 1
haveri
  • 29
  • 1
  • 2
  • 1
    When one has complete knowledge of the source and destination, of course. Save oneself a few precious cycles. – StoryTeller - Unslander Monica Apr 19 '17 at 15:35
  • 2
    Doesn't matter. `std::string` is better. – Captain Obvlious Apr 19 '17 at 15:36
  • ...but @StoryTeller, since that is impossible as long as the code has not been proven (hence has bugs, ub), defensive programming requires to always use `strncpy`. – Paul Ogilvie Apr 19 '17 at 15:37
  • What are you asking that is not already addressed by the answers to the question you linked? – John Bollinger Apr 19 '17 at 15:37
  • @PaulOgilvie Defensive programming requires `strlcpy` – Eugene Sh. Apr 19 '17 at 15:38
  • 1
    @PaulOgilvie - What is there to prove when copying c-string literals to buffers of a known size!? :) – StoryTeller - Unslander Monica Apr 19 '17 at 15:38
  • strncpy is better than strcpy but still it's a debate. I prefers to use strncpy instead of strcpy. – danglingpointer Apr 19 '17 at 15:39
  • @StoryTeller, that some increased the string literal that now no longer fits the buffer. (Probably Marketing wanted a nicer message, or so.) – Paul Ogilvie Apr 19 '17 at 15:40
  • @PaulOgilvie - Our complete knowledge has changed, but it's still complete. There's also the matter of the string literal being a poor choice as a user visible label. With i18n to consider, those things shouldn't be hard coded as literals anyway :) – StoryTeller - Unslander Monica Apr 19 '17 at 15:43
  • 3
    Your code does, as you say, leave room for the string terminator, but it doesn't put it in, so the resulting string is unterminated. You've just built yourself a trap. – Pete Becker Apr 19 '17 at 16:04
  • @PeteBecker [comment](http://stackoverflow.com/questions/43500151/isnt-strncpy-better-than-strcpy#comment74055761_43500151) is key! OP was under the false assumption that the code snippet was safe (it formed a string) because `strncpy()` was used and instead it is a problem when code uses `dest` as a string. – chux - Reinstate Monica Apr 19 '17 at 16:44
  • @JohnBollinger: To understand when would one use strcpy instead of strncpy. – haveri Apr 19 '17 at 17:16
  • If you are fine with writing beyond the end of a buffer, use `strcpy`. If you are more at ease with reading beyond the end of an array, use `strncpy`. If you wish to write well defined code, use `strncpy` and explicitly zero-terminate the destination buffer. – IInspectable Apr 20 '17 at 08:43
  • @PeteBecker: strncpy automatically adds in the null character if sizeof(dest) > sizeof(src). So, dest would then be "Hell". – haveri Apr 20 '17 at 15:00
  • @anusha -- RTFM. The effect of `std::strncpy` does not depend on the size of the destination array. It depends on **how many characters you tell it to copy**, and if it hits that limit before seeing a terminator in the source array, the destination **does not get a terminator**. `std::strncpy` is **not** a "safe" replacement for `std::strcpy` under any sensible definition of "safe". – Pete Becker Apr 20 '17 at 16:10
  • @PeteBecker: Maybe it's you who should do it. The whole reason why I do sizeof(dest)-1, is just so strncpy appends in the NULL character for that 1 byte that I still have. – haveri Apr 20 '17 at 19:33
  • @anusha - PAY ATTENTION: your code **does not terminate the result string**. It tells `strncpy` to copy 4 characters, and since `strncpy` does not hit a terminator in the source string, it **stops** after the fourth character **without** writing a terminator. The result of the copy is something like `"Hell#(ALJLKJ"`, i.e., it has whatever random stuff is in memory starting at `dest[4]`, and any code that uses `dest` is very likely to access memory off the end of the array. That will not end well. – Pete Becker Apr 20 '17 at 19:40

3 Answers3

11

It is not better. Contrary to common belief strncpy was not created to replace strcpy or to be a safe version of it. It fails to null terminate the string when the source string is larger than the num parameter, so you have to do it manually. Like this:

strncpy(dst, src, num);
dst[num - 1] = 0;

Which requires 2 lines to achieve 1 simple goal and it is easy for developers to forget the second one.

Besides that, it always writes num characters (appends 0's if necessary) regardless of the sizes of the strings which can be a performance concern when dst is small and num is large.

Using strncat fixes the second problem of writing extra characters but still forces you to write 2 lines:

dst[0];
strncat(dst, src, num);

The function strlcpy fixes both of these problems but it is not a C standard library function so do not use it.

The right choice is snprintf which is guaranteed to null terminate the string and only writes the necessary amount of characters, even if it means truncating the source string.

snprintf(dst, size, "%s", src);
imreal
  • 10,178
  • 2
  • 32
  • 48
  • Agree `snprintf(dst, size, "%s", src);` is a superior alternative to `strncpy()` for typical use to limit copying. It does have a weakness in detecting truncated results that is cumbersome. (too long, encoding error and type change). – chux - Reinstate Monica Apr 19 '17 at 16:52
4

In C, strncpy has the advantage over strcpy that it does not overflow the buffer when the source is larger than the destination.

strncpy has the disadvantage that, when the source is larger than the destination, it does not terminate the buffer with a \0. So every call of strncpy must be followed with a statement terminating the buffer, such as

strncpy(dst, src, n);
dst[n-1]='\0';

User Eugene Sh points out that for defensive programming strlcpy must be used: "strlcpy() takes the full size of the destination buffer and guarantees NUL-termination."

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
1

In C++, use std::string rather than c-style strings unless performance in a particular area is critical, in which case performance test to see if it is more than a negligible difference. You can use std::string::reserve to minimize allocations when you know the size up front.

In my opinion, 85% of bugs are caused by c-style strings. std::string is much safer and is less error prone.

In C, you won't have std::string available.

If you have to use c-style strings, then I'd prefer strncpy, because at least it asks for the size and makes you think about the size, rather than just overflowing.

Christopher Pisz
  • 3,757
  • 4
  • 29
  • 65
  • 1
    Of course, one must also use C strings when one is programming in C, and not C++. – John Bollinger Apr 19 '17 at 15:42
  • `My opinion cannot be inaccurate information, it is my opinion.` No, that's not at all true. Saying "In my opinion, *insert random made-up statistics here*" means your opinion is simply **inaccurate**. Regardless of whether it's an opinion or a "fact", it's made-up and it's wrong. – MD XF Apr 19 '17 at 19:25
  • For your answer to be accurate, you could rephrase that to say something like "In my *experience*, 85% of *bugs*..." or "In my code, 85% of bugs..." – MD XF Apr 19 '17 at 19:26
  • 1
    Sounds like flamewar bait to me. You can feel free to disagree with my opinion in the comments. You don't get to solely decide what is true and what is not, and edit it out in someone else's answer. I prefaced it with "in my opinion", I see no difference between that and "in my experience." It definitely is not "in my code", as I don't use c-style strings if I can help it. I just get to fix other people's bug riddled code for 20 years along the way. Posting a craw of the bug trackers for 7 companies (which I have done) to show 85% of bugs come from c-style strings is not reasonable here. – Christopher Pisz Apr 19 '17 at 19:35
  • See http://stackoverflow.com/help/editing – Christopher Pisz Apr 19 '17 at 19:41
  • `strncpy` doesn't prevent overflows. It merely exchanges writes past the end with reads past the end. It doesn't zero-terminate the destination for all cases where `strcpy` would have been problematic. You should at least point those dangers out. – IInspectable Apr 20 '17 at 08:17