2

When I run some code on my machine then it behaves as I expect it to.

When I run it on a colleagues it misbehaves. This is what happens.

I have a string with a value of:

croc_data_0001.idx

when I do a strncpy on the string providing 18 as the length my copied string has a value of:

croc_data_0001.idx♂

If I do the following

myCopiedString[18]='\0';
puts (myCopiedString);

Then the value of the copied string is:

croc_data_0001.idx

What could be causing this problem and why does it get resolved by setting the last char to \0?

hmjd
  • 120,187
  • 20
  • 207
  • 252
Dunc
  • 7,688
  • 10
  • 31
  • 38
  • 2
    `strncpy` does **not** properly terminate the destination string. It is not meant to be used as a replacement to `strcpy`! Also **Undefined Behaviour** (using `printf` or `puts` with something not a string) can manifest itself as you expect ;) – pmg Feb 27 '12 at 12:13

5 Answers5

5

According to http://www.cplusplus.com/reference/clibrary/cstring/strncpy/

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 to the end of destination, so destination will only be null-terminated if the length of the C string in source is less than num.

Thus, you need to manually terminate your destination with '\0'.

Alexander Pavlov
  • 31,598
  • 5
  • 67
  • 93
  • On a sidenote, debug builds tend to "zero out" uninitialized memory, so this may also affect your results (i.e. it works cleanly in the debug mode but displays weird characters in the release mode.) – Alexander Pavlov Feb 27 '12 at 12:24
1

strncpy does not want the size of the string to be copied, but the size of the target buffer.

In your case, the target buffer is 1 too short, disabling strncpy to zero-terminate the string. So everything that is behind the string resp. position 18 and is non-zero will be treated as belonging to the string.

Normally, functions taking a buffer size are called with exactly that, i. e.

char dest[50];
strncpy(dest, "croc_data_0001.idx", sizeof dest);

With this and an additional

dest[sizeof dest - 1] = '\0';

the string will always be 0-terminated.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • The question doesn't say what the size of the target buffer is, so you can't draw conclusions from that. – Mr Lister Feb 27 '12 at 12:37
  • No, but if I take the value given to `strncpy()` as the target buffer size (and from the view of this function, it is the case), I can only have the conclusion said. – glglgl Feb 27 '12 at 18:01
1

I think the C standard describes this function in a clearer manner than the links others have posted.

ISO 9899:2011

7.24.2.4 The strncpy function

char *strncpy (char * restrict s1,
               const char * restrict s2,
               size_t n);

The strncpy function copies not more than n characters (characters that follow a null character are not copied) from the array pointed to by s2 to the array pointed to by s1. If copying takes place between objects that overlap, the behavior is undefined.

If the array pointed to by s2 is a string that is shorter than n characters, null characters are appended to the copy in the array pointed to by s1, until n characters in all have been written.

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

strncpy does not always add a \0. See http://www.cplusplus.com/reference/clibrary/cstring/strncpy/

So either clear out your destination buffer beforehand, or always add the \0 yourself, or use strcpy.

If the question is: "why does uninitialised memory on my machine have different content than on another machine", well, one can only guess.

Edit changed wording somewhat; see comment.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
  • Yes it does automatically add \0, but only in case 'n' isn't as large as the buffer. "Padding with zeroes" means adding null terminations on all unused memory cells. That C++ reference is rather poorly worded. – Lundin Feb 27 '12 at 12:28
  • OK, except that you mean "only in case 'n' is larger that the source string"! – Mr Lister Feb 27 '12 at 12:41
  • No. In case you have `str[2]` and `strncpy(str,"hi",2)`, then n=2, N is as large as the buffer. There isn't any space left for trailing '\0' so none is added (bug). strcpy() would have attempted to write a trailing '\0' outside of the buffer and then crashed the program (bug). – Lundin Feb 27 '12 at 12:59
  • `strncpy` isn't concerned with the size of the buffer. Its function is not to provide a "buffer-size-safe" alternative to `strcpy`, but to copy fragments of larger strings into other strings. The concept of "protection against buffer overruns" didn't exist when these functions were written. – Mr Lister Feb 27 '12 at 13:07
  • My point is that the passed string in my example is 3 bytes but n=2. – Lundin Feb 27 '12 at 13:30
0

how much space have been alloted to myCopiedString variable? if its more than the length of the source string, then make sure you use bzero to clear out the destination variable.

Amey
  • 55
  • 1
  • 2
  • 5