This week one problem was discussed by my colleague regarding memory:
Sample code 1:
int main()
{
#define Str \"This is String.\"
char dest[1
The C Standard specifies strncpy this way:
7.24.2.4 The
strncpyfunctionSynopsis
#includechar *strncpy(char * restrict s1, const char * restrict s2, size_t n); Description
The
strncpyfunction copies not more thanncharacters (characters that follow a null character are not copied) from the array pointed to bys2to the array pointed to bys1.If copying takes place between objects that overlap, the behavior is undefined.
If the array pointed to by
s2is a string that is shorter thanncharacters, null characters are appended to the copy in the array pointed to bys1, untilncharacters in all have been written.Returns
The
strncpyfunction returns the value ofs1.
These semantics are widely misunderstood: strncpy is not a safe version of strcpy, the destination array is NOT null terminated if the source string is longer than the n argument.
In your example, this n argument is larger than the size of the destination array: the behavior is undefined because characters are written beyond the end of the destination array.
You can observe this is the first example as the buff array is positioned by the compiler just after the end of the dest array in automatic storage (aka on the stack) and is overwritten by strncpy. The compiler could use a different method so the observed behavior is by no means guaranteed.
My advice is to NEVER USE THIS FUNCTION. An opinion shared by other C experts such as Bruce Dawson: Stop using strncpy already!
You should favor a less error-prone function such as this one:
// Utility function: copy with truncation, return source string length
// truncation occurred if return value >= size argument
size_t bstrcpy(char *dest, size_t size, const char *src) {
size_t i;
/* copy the portion that fits */
for (i = 0; i + 1 < size && src[i] != '\0'; i++) {
dest[i] = src[i];
}
/* null terminate destination unless size == 0 */
if (i < size) {
dest[i] = '\0';
}
/* compute necessary length to allow truncation detection */
while (src[i] != '\0') {
i++;
}
return i;
}
You would use it this way in your example:
int main(void) {
#define Str "This is String."
char dest[12];
// the size of the destination array is passed
// after the pointer, just as for `snprintf`
bstrcpy(dest, sizeof dest, Str);
printf("Dest: %s\n", dest);
return 0;
}
Output:
This is a S