Pourquoi utiliser strncpy au lieu de strcpy?

Edit: j'ai ajouté la source pour l'exemple.

je suis tombé sur cet exemple :

char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;

/* This is how strcpy works */
printf("destination is originally = '%s'n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'nn", destination);

/* This is how strncpy works */
printf( "destination1 is originally = '%s'n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'n", destination1 );

qui a produit ce résultat:

destination is originally = 'abcdefg'
After strcpy, destination becomes '123456789'

destination1 is originally = 'abcdefg'
After strncpy, destination1 becomes '12345fg'

Qui me fait me demander pourquoi quelqu'un voudrait cet effet. Il semble qu'il serait source de confusion. Ce programme me fait penser que vous pourriez essentiellement copier sur le nom de quelqu'un (par exemple. Tom Brokaw) avec Tom Bro763.

Quels sont les avantages d'utiliser strncpy() plutôt que strcpy() ?

66
demandé sur Deduplicator 2009-08-11 09:17:58

10 réponses

strncpy combat le débordement de tampon en vous demandant d'y mettre une longueur. strcpy dépend d'un arrière " 151920920" , qui peut ne pas toujours se produire.

deuxièmement, pourquoi vous avez choisi de copier seulement 5 caractères sur 7 caractères chaîne est au-delà de moi, mais il produit le comportement attendu. Il ne s'agit que de copier les premiers caractères n , où n est le troisième argument.

les fonctions n sont toutes utilisées comme codage défensif contre les débordements de tampon. Veuillez les utiliser à la place des anciennes fonctions, telles que strcpy .

81
répondu Eric 2009-08-11 05:21:29

la fonction strncpy() a été conçue avec un problème très particulier à l'esprit: manipuler les chaînes stockées de la manière des entrées originales du répertoire UNIX. Ceux-ci utilisent un tableau de taille fixe, et un nul-terminator n'est utilisé que si le nom du fichier est plus court que le tableau.

c'est ce qui se cache derrière les deux bizarreries de strncpy() :

  • il ne met pas de nul-terminator sur la destination s'il est complètement rempli; et
  • il remplit toujours complètement la destination, avec nuls si nécessaire.

pour un "plus sûr strcpy() ", vous êtes mieux d'utiliser strncat() comme ceci:

if (dest_size > 0)
{
    dest[0] = '"151900920"';
    strncat(dest, source, dest_size - 1);
}

qui sera toujours nul-terminer le résultat, et ne copiera pas plus que nécessaire.

149
répondu caf 2009-08-11 06:32:02

bien que je connaisse l'intention derrière strncpy , ce n'est pas vraiment une bonne fonction. D'éviter à la fois. explique Raymond Chen .

personnellement, ma conclusion est simplement d'éviter strncpy et tous ses amis si vous avez affaire à des chaînes sans fin. Malgré le " str " dans le nom, ces fonctions ne produisent pas de chaînes à fin nulle. Ils convertissent une chaîne nulle en un tampon de caractères brut. En les utilisant, où un null-terminated string est attendu car le second buffer est tout à fait erroné. Non seulement vous ne parvenez pas à obtenir la terminaison nulle appropriée si la source est trop longue, mais si la source est courte, vous obtenez inutile null padding.

Voir aussi Pourquoi est-strncpy d'insécurité?

30
répondu Sinan Ünür 2017-03-24 13:43:25

strncpy n'est pas plus sûr que strcpy, il échange Juste un type de bogues avec un autre. En C, lorsque vous manipulez c strings, vous devez connaître la taille de vos tampons, il n'y a aucun moyen de l'éviter. strncpy était justifié pour la chose de répertoire mentionnée par d'autres, mais autrement, vous ne devriez jamais l'utiliser:

  • si vous connaissez la longueur de votre chaîne et de votre tampon, pourquoi utiliser strncpy ? C'est une perte de puissance de calcul au mieux (ajout inutile 0)
  • si vous ne connaissez pas les longueurs, alors vous risquez de tronquer vos cordes en silence, ce qui n'est pas beaucoup mieux qu'un débordement de tampon
25
répondu David Cournapeau 2009-08-11 06:27:20

ce que vous recherchez est la fonction strlcpy() qui termine toujours la chaîne avec 0 et initialise le buffer. Il est également capable de détecter les débordements. Seul problème, il n'est pas (vraiment) portable et n'est présent que sur certains systèmes (BSD, Solaris). Le problème avec cette fonction est qu'elle ouvre une autre boîte de Pandore comme on peut le voir dans les discussions sur http://en.wikipedia.org/wiki/Strlcpy

mon opinion personnelle est que il est beaucoup plus utile que strncpy() et strcpy() . Il a une meilleure performance et est un bon compagnon de snprintf() . Pour les plateformes qui ne l'ont pas, il est relativement facile à mettre en œuvre. (pour la phase de développement d'une application, je substitue ces deux fonctions ( snprintf() et strlcpy() ) à une version de piégeage qui interrompt brutalement le programme sur les débordements de buffer ou les troncations. Cela permet d'attraper rapidement les pires contrevenants. Surtout si vous travaillez sur une base de code de quelqu'un d'autre.

modifier: strlcpy() peut être mis en œuvre facilement:

size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
  size_t len = strlen(src);
  if(dstsize) {
    size_t bl = (len < dstsize-1 ? len : dstsize-1);
    ((char*)memcpy(dst, src, bl))[bl] = 0;
  }
  return len;
}
19
répondu Patrick Schlüter 2016-04-04 07:15:38

la fonction strncpy() est la plus sûre: vous devez passer la longueur maximale que le tampon de destination peut accepter. Sinon, il pourrait arriver que la chaîne de caractères source ne soit pas correctement terminée 0, auquel cas la fonction strcpy() pourrait écrire plus de caractères à destination, corrompant tout ce qui se trouve dans la mémoire après le tampon de destination. C'est le problème de dépassement de tampon utilisé dans de nombreux exploits

aussi pour les fonctions API POSIX comme read() qui ne met pas le 0 terminal dans le tampon, mais renvoie le nombre d'octets lus, vous pourrez soit mettre manuellement le 0, soit le copier en utilisant strncpy() .

dans votre exemple de code, index n'est en fait pas un index, mais un count - il indique combien de caractères au plus à copier de la source à la destination. S'il n'y a pas de octet null parmi les premiers n octets de source, la chaîne placée dans la destination ne sera pas terminée null

2
répondu CsTamas 2009-08-11 05:31:44

strncpy remplit la destination avec '\0 ' pour la taille de la source, même si la taille de la destination est plus petite....

page de manuel:

si la longueur de src est inférieure à n, strncpy() pads le reste de dest avec des octets nuls.

et pas seulement le reste...aussi après cela jusqu'à ce que n caractères soit atteindre. Et ainsi vous obtenez un débordement... (voir la page de man la mise en œuvre)

1
répondu Jeronimo 2013-11-01 17:02:16

ceci peut être utilisé dans beaucoup d'autres scénarios, où vous devez copier seulement une partie de votre chaîne originale vers la destination. En utilisant strncpy () vous pouvez copier une partie limitée de la chaîne originale par opposition à strcpy (). Je vois que le code que vous avez mis vient de publib.boulder.ibm.com .

0
répondu ARV 2009-08-11 05:29:15

cela dépend de nos besoins. Pour les utilisateurs de windows

nous employons strncpy chaque fois que nous ne voulons pas copier la chaîne entière ou nous voulons copier seulement n nombre de caractères. Mais strcpy copie toute la chaîne de caractères, y compris la terminaison du caractère null.

ces liens vous aideront à en savoir plus sur strcpy et strncpy et où l'on peut utiliser.

à propos de strcpy

à propos de strncpy

0
répondu Prakash 2016-07-05 07:33:42

la strncpy est plus sûr de la version de la fonction strcpy comme une question de fait, vous ne devriez jamais utiliser strcpy en raison de son potentiel de vulnérabilité de dépassement de tampon qui vous rend le système vulnérable à toutes sortes d'attaques

-8
répondu bashmohandes 2009-08-11 05:21:33