Estou escrevendo um pedaço de prática simples para comparar o uso de entre memcpy ou strncpy. Vejo que posso fazer essa cópia de string usando qualquer uma dessas duas funções:
char * strncpy ( char * destination, const char * source, size_t num );
e
void * memcpy ( void * destination, const void * source, size_t num );
Prática simples
char src[] = "Hello World";
char dst[20];
strncpy(dst, src, 5);
printf("%zu-", strlen(dst));
memcpy(dst, src, sizeof(dst));
printf("%zu-", strlen(dst));
strncpy(dst, src, 5);
printf("%zu", strlen(dst));
A saída real
5-11-11
Como posso entender que eles se comportam de forma diferente com respeito?
Em geral, como posso descobrir bytes relativos de blocos de memória diferentes copiados usando memcpy ou strncpy?
Quando a contagem se esgota antes que um caractere nulo seja encontrado na origem,
strncpy
não escreve um nulo de terminação no destino. Entãodst
não pode ser terminado em nulo, em cujo caso o comportamento destrlen
não é definido. No entanto, o fato de “5” ser impresso é consistente com odst
que acontece para conter um zero emdst[5]
.Seu
src
tem apenas 12 bytes, enquantosizeof(dst)
tem 20, então issomemcpy
tenta ler bytes de além desrc
. Novamente, o comportamento não está definido. Ele provavelmente copiou paradst
os 11 bytes de “Hello World”, o byte nulo seguinte e, então, oito bytes de qualquer coisa que estivesse na memória depois desrc
.Neste ponto,
dst
provavelmente contém os dados descritos acima, os 11 bytes de “Hello World” e o byte nulo seguinte, e isso faz comstrlen
que retorne 11.strncpy
não adiciona um NUL se não houver espaço suficiente. Comostrlen
requer uma string terminada em NUL, o primeiro uso destrlen
resulta em comportamento indefinido.O uso adequado
strncpy
requer a garantia de um NUL de terminação, o que pode ser feito usando o seguinte:stpncpy
é similar astrncpy
, exceto que retorna um ponteiro para onde parou de escrever em vez de preencher o resto do buffer com NULs. Então também poderia usar o seguinte:Há um segundo problema. Suas
memcpy
tentativas de copiar 20 bytes, mas o objeto do qual você está copiando ocupa apenas 12. Então esse também é um comportamento indefinido. Não copie mais bytes do que você tem!