strncpy(3)
Fonction de la bibliothèque C
Copie au plus n octets et complète avec des octets nuls. Si la source est trop longue, la destination n'est pas terminée : strncpy n'est pas un strcpy sûr.
#include <string.h>
char *strncpy(char *restrict dst, const char *restrict src, size_t n);Description
strncpy écrit toujours exactement n octets dans dst. Elle copie les octets de src jusqu'à son '\0', sans dépasser n. Si la source est plus courte que n, elle complète le reste de la destination avec des octets nuls. Si la source fait n caractères ou plus, elle copie les n premiers et s'arrête là, sans ajouter de '\0'.
Ce comportement s'explique par son usage d'origine : remplir des champs de taille fixe complétés par des zéros, comme ceux des fichiers de connexion utmp sous Unix. La page de manuel Linux la présente d'ailleurs comme une copie qui produit une suite de caractères complétée de zéros, pas une chaîne.
Valeur de retour
dst. Rien n'indique si la source a été tronquée : pour le savoir, compare strlen(src) à n avant l'appel.
Pièges
Le piège principal est l'octet nul manquant. Après strncpy(dst, src, sizeof dst) avec une source trop longue, dst n'est pas une chaîne : strlen(3) ou un printf("%s") liront au-delà du tableau. La parade classique est de copier avec n égal à la taille du tableau, puis d'écrire soi-même le terminateur dans la dernière case, comme dans l'exemple : la chaîne est alors tronquée, mais terminée.
GCC repère ce cas quand il connaît les deux tailles, et prévient avec -Wstringop-truncation comme dans l'exemple. Quand la source n'est connue qu'à l'exécution, il ne peut pas savoir s'il y aura troncature.
Le remplissage a un coût : strncpy(buf, "a", 4096) écrit 4 096 octets, dont 4 095 zéros. Pour copier une petite chaîne dans un grand tampon, c'est du travail inutile.
Comme pour strcpy(3), src et dst ne doivent pas se chevaucher.
Pour tronquer proprement une chaîne dans un tableau, snprintf(dst, sizeof dst, "%s", src) termine toujours la destination et renvoie la longueur qu'il aurait fallu, ce qui permet de détecter la troncature.
Exemple
Le programme affiche chaque octet écrit, avec un point à la place de chaque '\0'.
#include <stdio.h>#include <string.h>
static void dump(const char *buf, size_t n){ for (size_t i = 0; i < n; i++) putchar(buf[i] == '\0' ? '.' : buf[i]); putchar('\n');}
int main(void){ char court[8]; char long_[4];
strncpy(court, "git", sizeof court); dump(court, sizeof court); strncpy(long_, "docker", sizeof long_); dump(long_, sizeof long_); long_[sizeof long_ - 1] = '\0'; printf("%s\n", long_); return 0;}$ gcc -Wall -Wextra ncopie.c -o ncopiencopie.c: In function 'main':ncopie.c:18:5: warning: 'strncpy' output truncated copying 4 bytes from a string of length 6 [-Wstringop-truncation] 18 | strncpy(long_, "docker", sizeof long_); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~$ ./ncopiegit.....dockdoc"git" est plus court que 8 : trois lettres, puis cinq octets nuls de remplissage. "docker" est plus long que 4 : quatre lettres, aucun terminateur, et dock n'est pas une chaîne. La ligne 20 écrit le '\0' dans la dernière case, ce qui sacrifie le k mais donne une chaîne valide, doc.
strncpy
Écris gm_strncpy, qui complète dst avec des octets nuls quand src est court et n'ajoute aucun terminateur quand src remplit les n octets.