1
votes

Est-ce un bon moyen d'utiliser strcpy?

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?


4 commentaires

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."


3 Réponses :


4
votes

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:

  1. le code qui fait en sorte que la variable pointeur pointe vers suffisamment d'espace pour la chaîne que vous êtes sur le point d'y copier, et
  2. l'appel réel à 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';


9 commentaires

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.



5
votes

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 >


0 commentaires

3
votes

Il y a quelques problèmes avec le code publié:

  • vous ne vérifiez pas si malloc () a réussi: si malloc () échoue et renvoie NULL , en passant ce pointeur nul à strcpy a un comportement indéfini.
  • la dernière instruction 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");


0 commentaires