question de documentation strncpy

Concernant strncpy : http://www.cplusplus.com/reference/clibrary/cssortingng/strncpy/ , il est mentionné ce qui suit:

Aucun caractère null n’est ajouté implicitement à la fin de la destination. La destination ne sera terminée par null si la longueur de la chaîne C dans la source est inférieure à num.

Que veut dire cette phrase?

Cela signifie que, par exemple, si votre chaîne source strncpy 20 caractères plus un terminateur null et que votre strncpy spécifie moins de 21 caractères, la chaîne cible ne sera pas complétée par un caractère null.

Cela est dû à la façon dont cela fonctionne: strncpy garantit qu’il écrira exactement N octets, où N est la valeur de longueur transmise.

Si la longueur de la chaîne source (sans octet nul) est inférieure à cette valeur, la zone de destination sera complétée par des valeurs NULL. Si elle est égale ou supérieure, vous n’obtiendrez pas de valeur NULL à la destination.

Cela signifie que ce n’est pas techniquement une chaîne en C que vous obtenez. Cela peut être résolu avec un code comme:

 char d[11]; // Have enough room for ssortingng and null. strncpy (d, s, 10); // Copy up to 10 bytes of ssortingng, null the rest. d[10] = '\0'; // Then append null manually in case s was too long. 

Vous allouez 11 octets (index de tableau 0..10), copiez-en 10 au maximum (index 0..9), puis définissez le 11ème (index 10) sur null.

Voici un diagramme montrant les trois possibilités pour écrire des chaînes de différentes tailles dans une zone de 10 caractères avec strncpy (d, s, 10). représente un octet nul:

 sd ------------- ---------- Hello. Hello..... Hello Fred. Hello Fred Hello George. Hello Geor 

Notez que dans les deuxième et troisième cas, aucun octet nul n’est écrit. Par conséquent, si vous traitez d comme une chaîne, vous serez probablement déçu du résultat.

La chaîne "foo" a 3 caractères + 1 null-terminateur (elle est stockée sous la forme "foo\0" ), ce qui donne une longueur totale de 4. Si vous appelez strncpy avec n=3 (ou moins), elle n’appenda pas de valeur null se termine à la fin de la chaîne cible, mais ne copie que "foo" . Tenter d’imprimer la chaîne résultante entraînera un comportement indéfini en raison de l’absence d’un terminateur nul signalant la fin de la chaîne.

Vous devez faire très attention à cela et soit en passer un plus grand que le maximum de la source, soit append le terminateur nul vous-même.

Cela signifie qu’il copie le null final de la chaîne source, mais n’ajoute pas de null terminal si la chaîne source ne correspond pas à la destination.

En C, les chaînes stockées en tant que tableaux de caractères sont terminées par un caractère null, ce qui signifie qu’un 0 supplémentaire est ajouté à la fin, ce qui marque la fin de la chaîne et peut être utilisé ultérieurement pour déterminer la longueur de la chaîne. Donc, la chaîne "hello" ressemble à ceci en mémoire:

 char hello[] = {'h', 'e', 'l', 'l', 'o', 0}; 

Normalement, lorsque vous copiez une chaîne, le caractère null doit également être copié. Donc, la mémoire nécessaire pour le tampon de chaîne est sa longueur + 1 (par exemple (strlen(hello) + 1) * sizeof(char) ).

La fonction strncpy vous permet de copier autant de caractères que possible dans le tampon fourni. Au cas où le tampon que vous avez fourni n’est pas assez grand pour contenir cet extra null , il ne sera pas ajouté. Ou si la chaîne est coupée, elle ne sera pas terminée par un zéro.

 char hello[] = "hello"; // 5 characters, 6 bytes long char hel[3]; strncpy(hel, hello, 3); // hel is {'h', 'e', 'l'} 

Vous devez toujours être prudent après avoir appelé strncpy , car le résultat pourrait ne pas être une chaîne C valide. Si la chaîne n’est pas terminée par un caractère NULL, il est impossible de connaître sa longueur et la plupart des fonctions de manipulation de chaîne échoueraient ou feraient quelque chose d’inattendu.

Cela signifie que seuls des octets num seront copiés du tampon source vers le tampon de destination. donc, si la longueur de la chaîne source est supérieure ou égale à num , l’octet de fin NULL ne sera pas copié et le résultat n’aura pas d’octet de fin NULL, ce qui est dangereux.

Il est recommandé d’utiliser strlcpy à la place.

La sémantique de strncpy() , même lorsqu’elle est expliquée précisément comme dans la référence C ++ ci-dessus, est largement mal comprise. Le comportement de cette fonction est contre-intuitif et sujet aux erreurs.

Pour éviter tout problème lors de son utilisation ou plus loin dans le processus de développement, il existe une solution simple lorsque le responsable de la maintenance interprète mal le code et ajoute des bogues plus subtils. NE JAMAIS JAMAIS UTILISER CETTE FONCTION .

Vous pouvez lire plus de détails à ce sujet dans cet article de Bruce Dawson .

Pour répondre à votre question: si la chaîne source est plus longue que la taille passée en tant que troisième argument (correspondant généralement à la taille du tampon de destination), la fonction copiera les caractères de taille dans la destination et aucun octet nul ne sera présent parmi ceux-ci. Appelant strlen(destination); invoquera alors un comportement non défini car il tentera de lire au-delà de la fin du tableau jusqu’à ce qu’il trouve un terminateur nul. Ce comportement spécifique est ce qui rend strncpy si sujet aux erreurs.