J'essaye d'utiliser strcpy
; est-ce un bon moyen de le faire?
char *stringvar; stringvar = malloc(strlen("mi string") + 1); strcpy(stringvar, "mi string"); stringvar[strlen("mi string")] = '\0';
Que pensez-vous?
3 Réponses :
Vous n'avez pas besoin de la dernière ligne
stringvar = malloc(strlen("mi string" + 1));
strcpy
s'occupe de cela pour vous.
Dans le vrai code, vous devez absolument vérifiez la valeur de retour de malloc
pour vous assurer qu'elle n'est pas NULL
.
À part cela, votre code est correct. En particulier, vous avez le + 1
vital dans l'appel à malloc
. strlen
vous donne la longueur de la chaîne non incluant le caractère de fin '\ 0'
, mais strcpy
va pour l'ajouter, vous devez donc absolument lui allouer de l'espace.
Le problème avec strcpy
- le problème fatal, disent certains - est qu'au moment où vous appelez strcpy
, vous n'avez aucun moyen de dire à strcpy
la taille du tableau de destination. Il est de votre responsabilité de rendre le tableau suffisamment grand et d'éviter le débordement. strcpy
est incapable, à lui seul, d'empêcher le dépassement de la mémoire tampon - et bien sûr, si la destination déborde, c'est un gros problème.
Alors la question est, comment pouvez-vous assurez-vous - absolument assurez - que tous les appels à strcpy
dans tout le code que vous écrivez sont corrects? Et comment pouvez-vous vous assurer que plus tard, quelqu'un qui modifiera votre programme ne gâchera pas accidentellement les choses?
En gros, si vous utilisez strcpy
du tout, vous voulez arranger ces deux choses sont juste à côté de l'autre:
strcpy
qui copie la chaîne dans ce pointeur. Donc, votre code
stringvar = malloc(strlen(inputstring)); strcpy(stringvar, inputstring);
est assez proche de cet idéal.
Je sais que votre code n'est qu'un exemple, mais il Explorons-nous le problème, et si plus tard, quelqu'un modifie votre programme par accident? Et si quelqu'un le change en
char *inputstring = "mi string"; char *stringvar = malloc(strlen(inputstring) + 1); if(stringvar == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } strcpy(stringvar, inputstring);
De toute évidence, nous avons un problème. Donc, pour être absolument sûr qu'il y a de la place pour la chaîne que nous copions, c'est encore mieux, je pense, si la chaîne que nous copions est dans une variable, il est donc évident que la chaîne que nous 're copying est la même chaîne pour laquelle nous avons alloué de l'espace.
Voici donc ma version améliorée de votre code:
stringvar = malloc(strlen("mi string") + 1); strcpy(stringvar, "mi string asombroso");
(Malheureusement, la vérification d'un retour NULL
de malloc
fait obstacle à l'objectif d'avoir l'appel strcpy
juste à côté du malloc
call.)
Fondamentalement, votre code est une implémentation de la fonction de bibliothèque C strdup
, qui prend une chaîne que vous lui donnez et renvoie une copie dans la mémoire de malloc
.
One plus de chose. Vous étiez préoccupé par le + 1
dans le tout à malloc
, et comme je l'ai dit, c'est correct. Une erreur assez courante est
stringvar = malloc(strlen("mi string") + 1); strcpy(stringvar, "mi string");
Cela ne parvient pas à allouer de l'espace pour le \ 0
, donc lorsque strcpy
ajoute le \ 0 cela déborde de l'espace alloué, donc c'est un problème.
Et cela dit, assurez-vous de ne pas écrire accidentellement
stringvar[strlen("mi string")] = '\0';
Vous ne voulez sûrement pas déclarer (puis utiliser) char inputstring = "mi string"
, même si cela compile probablement ;-).
J'ai lu le post autre, dis-le strlen ("mi string") == 9 + '\ 0', est-ce que strlen dit 10 ou 9?
@ PeterA.Schneider Je ne l'ai sûrement pas fait. Fixé. Merci.
Eh bien, cela devrait toujours être const, et la ligne devrait se terminer par un point-virgule ... J'ai appris à la difficulté de ne pas publier de code non exécuté (et encore moins non compilé) ...
@Roman strlen
renvoie la longueur des caractères de la chaîne, pas en comptant le '\ 0'
. donc strlen ("mi string")
vaut 9, pas 10.
je demande besoin + 1 en malloc?
@ PeterA.Schneider J'ai aussi appris cette leçon il y a longtemps. Le problème est que parfois je triche encore ... :-(
@Roman Oui, c'est vrai.
@Roman en effet, c'est nécessaire. L'omettre est une erreur courante et fatale.
Il y a exactement un bogue dedans: vous ne vérifiez pas l'échec de malloc.
En dehors de cela, il est répétitif et sujet aux erreurs.
Et écraser le terminateur par le terminateur est inutile.
De plus, le recalcul répété de la longueur de la chaîne est coûteux.
Quoi qu'il en soit, comme vous devez déjà déterminer la longueur, préférez memcpy ()
sur strcpy ()
.
Ce que vous devez faire est de l'extraire dans une fonction, appelons-la strdup ()
(c'est le nom POSIX et le prochain standard C le donnent):
char* strdup(const char* s) { size_t n = strlen(s) + 1; char* r = malloc(n); if (r) memcpy(r, s, n); return r; } char* stringvar = strdup("mi string"); if (!stringvar) handle_error();
p >
Il y a quelques problèmes avec le code publié:
malloc ()
a réussi: si malloc ()
échoue et renvoie NULL
, en passant ce pointeur nul à strcpy
a un comportement indéfini. stringvar [strlen ("mi string")] = '\ 0';
est inutile: strcpy
copie le terminateur nul à la fin de la chaîne source, faisant du tableau de destination une chaîne C appropriée. Voici une version corrigée:
char *stringvar = strdup("mi string");
Notez qu'il serait légèrement préférable de stocker la taille d'allocation et de ne pas utiliser strcpy code >:
char *stringvar; size_t size = strlen("mi string") + 1; if ((stringvar = malloc(size)) != NULL) memcpy(stringvar, "mi string", size);
En effet, il serait encore plus simple et plus sûr d'utiliser strdup ()
, disponible sur les systèmes compatibles POSIX, qui effectue exactement les étapes ci-dessus :
#include <stdlib.h> #include <string.h> ... char *stringvar; if ((stringvar = malloc(strlen("mi string") + 1)) != NULL) strcpy(stringvar, "mi string");
Je vote pour fermer cette question comme hors sujet car il s'agit de réviser un code de travail
critique non, je demande bien
c'est une critique
La révision du code concerne les questions qui portent sur "Dites-moi comment améliorer cette goutte de code". Cette question n'est pas hors sujet sur Stack Overflow car elle demande si un moyen est bon ou non. Il n'est pas non plus avisé, car la réponse est sans équivoque "Non, ce n'est pas un bon moyen. En fait, vous n'avez pas du tout besoin d'utiliser
strcpy
pour cela."