il y a aussi strdupa () (dans la bibliothèque GNU C), une belle fonction similaire à strdup (), mais alloue de la mémoire sur la pile. Votre programme n'a pas besoin de libérer la mémoire explicitement comme dans le cas avec strdup (), il sera libéré automatiquement lorsque vous quitterez la fonction où strdupa () a été appelée
dmityugov
11
strdupaest dangereux et ne doit pas être utilisé sauf si vous avez déjà déterminé qu'il strlenest très petit. Mais alors vous pouvez simplement utiliser un tableau de taille fixe sur la pile.
R .. GitHub STOP HELPING ICE
4
@slacker google translate n'est pas utile ... Que signifie strdup/ strdupasignifie en polonais?
Exactement ce à quoi cela ressemble, en supposant que vous êtes habitué à la façon abrégée dont C et UNIX attribuent les mots, il duplique les chaînes :-)
En gardant à l'esprit que cela ne fait pas partie de la norme ISO C elle-même (a) (c'est une chose POSIX), cela fait en fait la même chose que le code suivant:
char*strdup(constchar*src){char*dst = malloc(strlen (src)+1);// Space for length plus nulif(dst == NULL)return NULL;// No memory
strcpy(dst, src);// Copy the charactersreturn dst;// Return the new string}
En d'autres termes:
Il essaie d'allouer suffisamment de mémoire pour contenir l'ancienne chaîne (plus un caractère «\ 0» pour marquer la fin de la chaîne).
Si l'allocation échoue, il met errnoà ENOMEMet retourne NULLimmédiatement. La définition de errnoto ENOMEMest quelque chose qui se mallocfait dans POSIX, nous n'avons donc pas besoin de le faire explicitement dans notre strdup. Si vous n'êtes pas conforme à POSIX, ISO C n'exige pas réellement l'existence de ENOMEMdonc je ne l'ai pas inclus ici (b) .
Sinon, l'allocation a fonctionné, nous copions donc l'ancienne chaîne dans la nouvelle chaîne (c) et renvoyons la nouvelle adresse (que l'appelant est responsable de libérer à un moment donné).
Gardez à l'esprit que c'est la définition conceptuelle. Tout écrivain de bibliothèque digne de ce nom peut avoir fourni un code fortement optimisé ciblant le processeur particulier utilisé.
(a) Cependant, les fonctions commençant par stret une lettre minuscule sont réservées par la norme pour les directions futures. De C11 7.1.3 Reserved identifiers:
Chaque en-tête déclare ou définit tous les identificateurs répertoriés dans sa sous-clause associée, et * déclare ou définit facultativement les identificateurs répertoriés dans sa future sous-clause de directions de bibliothèque associées. **
Les orientations futures pour string.hse trouvent dans C11 7.31.13 String handling <string.h>:
Les noms de fonctions commençant par str, memou wcset une lettre minuscule peuvent être ajoutés aux déclarations dans l'en- <string.h>tête.
Donc, vous devriez probablement l'appeler autrement si vous voulez être en sécurité.
(b) Le changement serait essentiellement remplacé if (d == NULL) return NULL;par:
if(d == NULL){
errno = ENOMEM;return NULL;}
(c) Notez que j'utilise strcpypour cela car cela montre clairement l'intention. Dans certaines implémentations, il peut être plus rapide (car vous connaissez déjà la longueur) à utiliser memcpy, car ils peuvent permettre de transférer les données en plus gros morceaux, ou en parallèle. Ou ce n'est peut-être pas le cas :-) Mantra d'optimisation # 1: "mesurer, ne pas deviner".
Dans tous les cas, si vous décidez de suivre cette voie, vous feriez quelque chose comme:
char*strdup(constchar*src){size_t len = strlen(src)+1;// String plus '\0'char*dst = malloc(len);// Allocate spaceif(dst == NULL)return NULL;// No memory
memcpy (dst, src, len);// Copy the blockreturn dst;// Return the new string}
Il convient de noter que, comme l'implémentation de l'exemple de Pax l'indique, strdup (NULL) n'est pas défini et n'est pas quelque chose que vous pouvez vous attendre à se comporter de manière prévisible.
détendez-vous
2
De plus, je pense que malloc () définirait errno, vous ne devriez donc pas avoir à le définir vous-même. Je pense.
Chris Lutz
5
@Alcot, strdupest pour les situations où vous souhaitez que la mémoire de tas soit allouée pour la copie de chaîne. Sinon, vous devez le faire vous-même. Si vous avez déjà avoir un tampon assez grand (malloc ou autrement), oui, utilisation strcpy.
paxdiablo
2
@acgtyrant: si, par norme, vous voulez dire la norme ISO (la vraie norme C), non, elle n'en fait pas partie. Il fait partie du standard POSIX. Cependant, il existe de nombreuses implémentations C qui le fournissent, bien qu'elles ne fassent pas officiellement partie de l'ISO C. Cependant, même si ce n'est pas le cas, les cinq lignes de cette réponse devraient être plus que suffisantes.
paxdiablo
2
Bon point, @chux, les mandats ISO ne sont { EDOM, EILSEQ, ERANGE }que des codes d'erreur requis. J'ai mis à jour la réponse pour en tenir compte.
paxdiablo
86
char* strdup(constchar* s){size_t len =1+strlen(s);char*p = malloc(len);return p ? memcpy(p, s, len): NULL;}
Peut-être que le code est un peu plus rapide qu'avec, strcpy()car le caractère \0n'a pas besoin d'être recherché à nouveau (il l'était déjà avec strlen()).
Merci. Dans ma mise en œuvre personnelle, je fais encore pire. return memcpy(malloc(len), s, len);car je préfère le crash sur l'allocation plutôt que l' NULLéchec de l'allocation.
Patrick Schlüter du
3
Le déréférencement de @tristopia NULLn'a pas à se bloquer; ce n'est pas défini. Si vous voulez être sûr qu'il se bloque, écrivez un emallocqui appelle abortfail.
Dave
Je le sais, mais mon implémentation est garantie de fonctionner uniquement sur Solaris ou Linux (par la nature même de l'application).
Patrick Schlüter
@tristopia: C'est bien d'avoir l'habitude de faire les choses de la meilleure façon. Prenez l'habitude d'utiliser emallocmême si ce n'est pas nécessaire sur Solaris ou Linux afin de pouvoir l'utiliser à l'avenir lorsque vous écrivez du code sur d'autres plates-formes.
ArtOfWarfare
51
Inutile de répéter les autres réponses, mais veuillez noter que cela strdup()peut faire tout ce qu'il veut d'un point de vue C, car il ne fait partie d'aucune norme C. Il est cependant défini par POSIX.1-2001.
Est strdup()portable? Non, non disponible dans un environnement non-POSIX (de toute façon implémentable de manière triviale). Mais dire qu'une fonction POSIX peut tout faire est assez pédant. POSIX est un autre standard aussi bon que les C et encore plus populaire.
PP
2
@BlueMoon Je pense que le fait est qu'une implémentation C qui ne revendique aucune conformité à POSIX peut toujours fournir une strdupfonction en tant qu'extension. Sur une telle implémentation, il n'y a aucune garantie que cela strdupse comporte de la même manière que la fonction POSIX. Je ne connais pas de telles implémentations, mais une implémentation légitime non malveillante pourrait fournir char *strdup(char *)des raisons historiques et rejeter les tentatives de passer a const char *.
Quelle est la différence entre la norme C et POSIX? Par standard C, vous voulez dire qu'il n'existe pas dans les bibliothèques standard C?
Koray Tugay
@KorayTugay Ce sont des normes différentes. Mieux vaut les traiter comme sans rapport, sauf si vous savez que la norme pour une fonction C particulière est conforme à la norme POSIX et que votre compilateur / bibliothèque est conforme à la norme pour cette fonction.
La strdup()fonction doit renvoyer un pointeur vers une nouvelle chaîne, qui est un doublon de la chaîne pointée par s1. Le pointeur renvoyé peut être transmis à free(). Un pointeur nul est renvoyé si la nouvelle chaîne ne peut pas être créée.
strdup () effectue l'allocation de mémoire dynamique pour le tableau de caractères, y compris le caractère de fin «\ 0» et renvoie l'adresse de la mémoire de tas:
Donc, ce qu'il fait, c'est nous donner une autre chaîne identique à la chaîne donnée par son argument, sans nous obliger à allouer de la mémoire. Mais nous devons encore le libérer plus tard.
Il crée une copie en double de la chaîne transmise en exécutant un malloc et strcpy de la chaîne transmise. Le tampon mallocé est renvoyé à l'appelant, d'où la nécessité de s'exécuter librement sur la valeur de retour.
La chose la plus précieuse qu'il fait est de vous donner une autre chaîne identique à la première, sans vous obliger à allouer de la mémoire (emplacement et taille) vous-même. Mais, comme indiqué, vous devez toujours le libérer (mais qui ne nécessite pas non plus de calcul de quantité.)
Donc, si vous voulez que la chaîne que vous avez copiée soit utilisée dans une autre fonction (telle qu'elle est créée dans la section tas), vous pouvez utiliser strdup, sinon strcpyc'est assez,
La fonction strdup () est un raccourci pour la duplication de chaîne, elle prend un paramètre comme une constante de chaîne ou un littéral de chaîne et alloue juste assez d'espace pour la chaîne et écrit les caractères correspondants dans l'espace alloué et renvoie finalement l'adresse de l'alloué espace à la routine d'appel.
strdupa
est dangereux et ne doit pas être utilisé sauf si vous avez déjà déterminé qu'ilstrlen
est très petit. Mais alors vous pouvez simplement utiliser un tableau de taille fixe sur la pile.strdup
/strdupa
signifie en polonais?Réponses:
Exactement ce à quoi cela ressemble, en supposant que vous êtes habitué à la façon abrégée dont C et UNIX attribuent les mots, il duplique les chaînes :-)
En gardant à l'esprit que cela ne fait pas partie de la norme ISO C elle-même (a) (c'est une chose POSIX), cela fait en fait la même chose que le code suivant:
En d'autres termes:
Il essaie d'allouer suffisamment de mémoire pour contenir l'ancienne chaîne (plus un caractère «\ 0» pour marquer la fin de la chaîne).
Si l'allocation échoue, il met
errno
àENOMEM
et retourneNULL
immédiatement. La définition deerrno
toENOMEM
est quelque chose qui semalloc
fait dans POSIX, nous n'avons donc pas besoin de le faire explicitement dans notrestrdup
. Si vous n'êtes pas conforme à POSIX, ISO C n'exige pas réellement l'existence deENOMEM
donc je ne l'ai pas inclus ici (b) .Sinon, l'allocation a fonctionné, nous copions donc l'ancienne chaîne dans la nouvelle chaîne (c) et renvoyons la nouvelle adresse (que l'appelant est responsable de libérer à un moment donné).
Gardez à l'esprit que c'est la définition conceptuelle. Tout écrivain de bibliothèque digne de ce nom peut avoir fourni un code fortement optimisé ciblant le processeur particulier utilisé.
(a) Cependant, les fonctions commençant par
str
et une lettre minuscule sont réservées par la norme pour les directions futures. DeC11 7.1.3 Reserved identifiers
:Les orientations futures pour
string.h
se trouvent dansC11 7.31.13 String handling <string.h>
:Donc, vous devriez probablement l'appeler autrement si vous voulez être en sécurité.
(b) Le changement serait essentiellement remplacé
if (d == NULL) return NULL;
par:(c) Notez que j'utilise
strcpy
pour cela car cela montre clairement l'intention. Dans certaines implémentations, il peut être plus rapide (car vous connaissez déjà la longueur) à utilisermemcpy
, car ils peuvent permettre de transférer les données en plus gros morceaux, ou en parallèle. Ou ce n'est peut-être pas le cas :-) Mantra d'optimisation # 1: "mesurer, ne pas deviner".Dans tous les cas, si vous décidez de suivre cette voie, vous feriez quelque chose comme:
la source
strdup
est pour les situations où vous souhaitez que la mémoire de tas soit allouée pour la copie de chaîne. Sinon, vous devez le faire vous-même. Si vous avez déjà avoir un tampon assez grand (malloc ou autrement), oui, utilisationstrcpy
.{ EDOM, EILSEQ, ERANGE }
que des codes d'erreur requis. J'ai mis à jour la réponse pour en tenir compte.Peut-être que le code est un peu plus rapide qu'avec,
strcpy()
car le caractère\0
n'a pas besoin d'être recherché à nouveau (il l'était déjà avecstrlen()
).la source
return memcpy(malloc(len), s, len);
car je préfère le crash sur l'allocation plutôt que l'NULL
échec de l'allocation.NULL
n'a pas à se bloquer; ce n'est pas défini. Si vous voulez être sûr qu'il se bloque, écrivez unemalloc
qui appelleabort
fail.emalloc
même si ce n'est pas nécessaire sur Solaris ou Linux afin de pouvoir l'utiliser à l'avenir lorsque vous écrivez du code sur d'autres plates-formes.Inutile de répéter les autres réponses, mais veuillez noter que cela
strdup()
peut faire tout ce qu'il veut d'un point de vue C, car il ne fait partie d'aucune norme C. Il est cependant défini par POSIX.1-2001.la source
strdup()
portable? Non, non disponible dans un environnement non-POSIX (de toute façon implémentable de manière triviale). Mais dire qu'une fonction POSIX peut tout faire est assez pédant. POSIX est un autre standard aussi bon que les C et encore plus populaire.strdup
fonction en tant qu'extension. Sur une telle implémentation, il n'y a aucune garantie que celastrdup
se comporte de la même manière que la fonction POSIX. Je ne connais pas de telles implémentations, mais une implémentation légitime non malveillante pourrait fournirchar *strdup(char *)
des raisons historiques et rejeter les tentatives de passer aconst char *
.De l' homme strdup :
La
strdup()
fonction doit renvoyer un pointeur vers une nouvelle chaîne, qui est un doublon de la chaîne pointée pars1
. Le pointeur renvoyé peut être transmis àfree()
. Un pointeur nul est renvoyé si la nouvelle chaîne ne peut pas être créée.la source
strdup () effectue l'allocation de mémoire dynamique pour le tableau de caractères, y compris le caractère de fin «\ 0» et renvoie l'adresse de la mémoire de tas:
Donc, ce qu'il fait, c'est nous donner une autre chaîne identique à la chaîne donnée par son argument, sans nous obliger à allouer de la mémoire. Mais nous devons encore le libérer plus tard.
la source
Il crée une copie en double de la chaîne transmise en exécutant un malloc et strcpy de la chaîne transmise. Le tampon mallocé est renvoyé à l'appelant, d'où la nécessité de s'exécuter librement sur la valeur de retour.
la source
strdup
etstrndup
sont définis dans les systèmes compatibles POSIX comme:La fonction strdup () alloue suffisamment de mémoire pour une copie de la chaîne
str
, effectue la copie et lui renvoie un pointeur.Le pointeur peut ensuite être utilisé comme argument de la fonction
free
.Si la mémoire disponible est insuffisante,
NULL
est renvoyée eterrno
est définie surENOMEM
.La fonction strndup () copie au maximum la plupart des
len
caractères de la chaîne,str
mettant ainsi fin à la chaîne copiée.la source
La chose la plus précieuse qu'il fait est de vous donner une autre chaîne identique à la première, sans vous obliger à allouer de la mémoire (emplacement et taille) vous-même. Mais, comme indiqué, vous devez toujours le libérer (mais qui ne nécessite pas non plus de calcul de quantité.)
la source
La déclaration:
est équivalent à (à part le fait que cela change les pointeurs):
Tandis que:
est équivalent à:
Donc, si vous voulez que la chaîne que vous avez copiée soit utilisée dans une autre fonction (telle qu'elle est créée dans la section tas), vous pouvez utiliser
strdup
, sinonstrcpy
c'est assez,la source
La fonction strdup () est un raccourci pour la duplication de chaîne, elle prend un paramètre comme une constante de chaîne ou un littéral de chaîne et alloue juste assez d'espace pour la chaîne et écrit les caractères correspondants dans l'espace alloué et renvoie finalement l'adresse de l'alloué espace à la routine d'appel.
la source
strdup
n'a pas besoin d'être une constante de chaîne, il doit être une chaîne C, c'est-à-dire un tableau terminé par null dechar
.