Reputation: 158
I tried to think how to make the function strncpy
and I met this problem.
char src[] = "123456789A";
char dest[10];
int n = 10;
printf("strncpy:%s\n", strncpy(dest, src, n));
Output
strncpy:123456789A123456789A
What is happening ?
Upvotes: 0
Views: 3510
Reputation: 145297
The quick answer: strncpy
is not your friend!
strncpy
is not a safer version of strcpy
, it will copy up to n
characters from src
and if src
is shorter, will pad the destination with null bytes up a total of n
characters.
If the source string has n
or more characters, the destination array will not be null terminated and passing to printf("%s",
will have undefined behavior: printf
will keep reading and printing bytes from memory after the end of dest
, until it finds a null byte or until this undefined behavior causes other unpredictable side effects...
The semantics of strncpy
are counter-intuitive and error-prone, avoid usng this function. See this article for a long answer: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
Upvotes: 3
Reputation: 311126
The array dest
does not contain a string because there is no enough space to accommodate the terminating zero '\0'
of the copied source string,
So to output the array use the following statement
printf("strncpy: %*.*s\n", n, n, strncpy(dest, src, n));
Otherwise you have to write something like the following
strncpy( dest, src, n )[sizeof( dest ) - 1] = '\0';
printf("strncpy: %s\n", dest );
In this case the destination array will not have the last character of the source string that will be overwritten by the zero character.
If you want to copy less characters than the size of the destination array then what to do after copying depends on the intention. If you want just to overwrite part of the string that is already stored in the destination array then nothing else you need to do. Otherwise set the character at position n
to zero character.
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
int main(void)
{
char src[] = "123456789A";
char dest[10] = "543216789";
size_t n = 5;
strncpy( dest, src, n );
printf("strncpy: %s\n", dest );
strncpy( dest, "Hello", n )[n] = '\0';
printf("strncpy: %s\n", dest );
return 0;
}
Its output is
strncpy: 123456789
strncpy: Hello
Upvotes: 1
Reputation: 3790
As others have said strncpy
won't include a terminating null if the destination size is the same as the string length. To give you a practical answer I normally just subtract one from the size of the destination using sizeof
to get the destination size including space for the terminator:
char src[] = "123456789A";
char dest[10];
printf("strncpy:%s\n", strncpy(dest, src, sizeof(dest) - 1));
Which gives an output of "strncpy:123456789" which is a character short of what you want but at least is defined behaviour and lets you know the destination buffer isn't large enough to contain the null terminator. So the final code that gives you the result you're after would be:
char src[] = "123456789A";
char dest[11];
printf("strncpy:%s\n", strncpy(dest, src, sizeof(dest) - 1));
Upvotes: 1