Myno
Myno

Reputation: 158

Problem on strncpy with source string longer than destination array

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

Answers (3)

chqrlie
chqrlie

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

Vlad from Moscow
Vlad from Moscow

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

PeterJ
PeterJ

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

Related Questions