3

I am reading this document, it says:

char *strncpy(char *destination, const char *source, size_t num);

Copy characters from string Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.

No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case, destination shall not be considered a null terminated C string (reading it as such would overflow).

destination and source shall not overlap (see memmove for a safer alternative when overlapping).

But I am confused by this statement:

in this case, destination shall not be considered a null terminated C string (reading it as such would overflow)

Since if num > strlen(source), it will pad with '\0' at the end, '\0' is actually a null (terminating) character in a string, why it shall not be considered a null-terminated C string?

I have written below code to verify:

  char from[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
  char to[1024];
  for (int i = 0; i < 1024; i++) {
      to[i] = 'e';
  }
  strncpy(to, from, 1024);
  printf("from %s\n", from);

It works fine with below output:

from hello
to hello
chqrlie
  • 131,814
  • 10
  • 121
  • 189
beetlej
  • 1,841
  • 4
  • 13
  • 27

3 Answers3

8

It's talking about the case when strlen(source) > num. It will only copy num chars, none of which is a NUL and it will not add a NUL.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
SpacedMonkey
  • 2,725
  • 1
  • 16
  • 17
  • 1
    ...and to make sure you *do* get a NUL terminator, use `strlcpy` instead of `strncpy`. – Danra Dec 09 '16 at 00:21
7

strncpy(dst, src, len) only adds a null terminator to dst if there is a null terminator in src within the first len bytes. Your code might seem to work, because there might or might not be a null character after the array to[]. A better test is:

char source[] = "source";
char dest[] = "destination";
strncpy(dest, source, 6);
printf("%s\n", dest);

The result should be:

sourceation

If you write strncpy(dest, source, 7) instead, then the output is just the word source.

G. Sliepen
  • 7,637
  • 1
  • 15
  • 31
3

The semantics of strncpy(), even when precisely explained as they are in the C++ reference above, are widely misunderstood. The behavior of this function is counterintuitive and error prone.

To avoid problems when using it or further down the development process, when the maintainer will misread the code and add more subtile bugs, there is a simple solution: NEVER EVER USE THIS FUNCTION.

You can read further details about this in this article by Bruce Dawson.

To answer your question: if the source string is longer than the size passed as a third argument (usually corresponding to the size of the destination buffer), the function will copy size characters to the destination and no null byte will be present among these. Calling strlen(destination); will then invoke undefined behavior because it will attempt to read beyond the end of the array until it finds a null terminator. This specific behavior is what makes strncpy so error prone.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • @EvilTeach: I updated the answer. It is important to deter newbies from using this error prone function. I have seen so many instances of misuse, even by experienced programmers... It acts as a universal bug attractor. – chqrlie Dec 09 '16 at 00:17
  • 1
    This is the best answer now. It's a shame the NEVER USE THIS FUNCTION can't be blinking between red and black. – EvilTeach Dec 09 '16 at 16:41
  • i would add strtok, atoi, atof and the whole scanf family to the list of functions to avoid. – EvilTeach Dec 09 '16 at 16:42
  • @EvilTeach: I agree about `strtok` and `scanf`. `atoi` and `atof` do not provide error checking but are much less problematic. `feof()` is pretty high on the list too, `sprintf()` should be replaced with `snprintf()`, `char` should be unsigned by default, 2s complement mandated, as well as 8/16/32/and 64 bit integer types, IEEE floating point... That would make C so much simpler. – chqrlie Dec 09 '16 at 21:36
  • @EvilTeach: `feof()` is almost systematically misused in `while (!feof(fp))`. `char` signed by default is inconsistent with `getc()` returning the values of the `unsigned char` type plus `EOF`, `strcmp()` comparing strings as arrays of `unsigned char` and functions from `` invoking undefined behavior for negative `char` values. – chqrlie Dec 09 '16 at 21:55