IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Retourner *proprement* un type string


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10
    Par défaut Retourner *proprement* un type string
    Bonjour à tous, après avoir passé de nombreuses heures à "googler" sur la question, je n'ai pas eu de réponse satisfaisante, je vais donc avoir besoin d'aide...

    D'abord, en C, y-a-t-il un moyen propre de retourner un char *, dans le but d'obtenir une nouvelle chaine ?

    1er exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    char * addch (char * ch1, char * ch2) {
        char buf[256] ;
        buf[0]='\0';
        strcat(buf,ch1);
        strcat(buf,ch2);
        return buf;
    }
    void main () {
       Char ptr[256], ch1[256], ch2[256];
       strcpy(ch1,"Hello ");
       strcpy(ch2,"World !");
       ptr = addch(ch1,ch2);
       ...
    }
    Je retourne l'addresse d'une varialbe locale => pas bien. Même avec un strcpy en sortie, on est pas à l'abri de voir la zone mémoire de buf écrasée lors de l'appel à strcpy (si on a pas de chance)...
    (Ce que je viens de dire est-il correct ?)

    2eme exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    char * addch (char * ch1, char * ch2) {
        char * buf;
        // je ne me souvient plus de la syntaxe exacte pour :
        <memalloc : allocation de mémoire pour buf> 
        buf[0]='\0';
        strcpy(buf,ch1);
        strcat(buf,ch2);
        return buf;
    }
    void main () {
       Char ptr[256], ch1[256], ch2[256];
       strcpy(ch1,"Hello ");
       strcpy(ch2,"World !");
       ptr = addch(ch1,ch2);
       ...
    }
    Là, il me semble que c'est mieux, sauf qu'en retour de fonction, comme ptr prennant la nouvelle valeur avait déja une allocation, celle-ci est donc "perdue" (cause de "memory leak") ?
    faut-il désallouer ptr avant l'appelle à la fonction ?
    Cette solution me semble lourde et peu pratique à appliquer, autant passer ptr comme paramètre supplémentaire (?), sauf qu'il est alors inutile de retourner une valeur, puisqu'on peux directement affecter la nouvelle chaine à ptr ...


    En C++ maintenant, avec la classe STL string, que se passe-t-il si je retourne une variable locale de type string dans l'exemple suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    string str1;
    str1 = addstr(str2,str3);
    Est ce que l'affectation de str1 avec l'opérateur = est une simple affectation de pointeur, ou est-ce que la chaine est recopiée à l'addresse adéquate dans la structure String ? Et même dans ce dernier cas, ne risquons nous pas de voir la chaine écrasée avant d'avoir été recopiée (comme dans le cas précédent en C) ?

    Etant donné que le problème semble "basic" et que je n'ai trouvé aucune réponse dans les forums/faqs, je dois avoir mal compris certains concepts en C/C++ concernant les appels aux fonctions / l'allocation mémoire / la gestion des pointeurs...

    Merci de votre aide !

  2. #2
    Rédacteur
    Avatar de bigboomshakala
    Homme Profil pro
    Consultant Web .NET
    Inscrit en
    Avril 2004
    Messages
    2 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Consultant Web .NET
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2004
    Messages : 2 077
    Par défaut
    comme tu n'utilises pas de pointeurs mais une classe (string) ce qui est retourné est un objet, donc no problemo

    Est ce que l'affectation de str1 avec l'opérateur = est une simple affectation de pointeur
    -> string str1 : pas d'étoile, pas de pointeur, pas de question d'alloc/désalloc à se poser, on affecte et c'est ok.
    un avantage du C++ face au C c'est l'objet. on peut la plupart du temps se passer de pointeurs et on n'a pas à s'inquiéter dans ce cas d'alloc/désalloc.

  3. #3
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    * C.1- Effectivement, ce qui est retrouné sera écrasé. C'est une certitude et non une question de chance. Ce quetu retournes pointe vers une zone de mémoire qui peut contenir n'importe quoi.
    Qui plus est, ptr est un tableau dans ton main, tu ne peux pas le réaffecter

    * C.2- C'est à l'appelant de réaliser la libération qui correspond à l'allocation effectuée.
    De plus, ton code est potentiellement vulnérable aux buffer overloads.

    Tu as une troisième solution : tu passes un buffer à ta fonction, ainsi que la taille du buffer. cf l'interface de strcpy.


    * C++.
    La classe de la SL (sans T) std::string a une sémantique de valeur -- en particulier, c'est copiable. Cela va se manipuler comme les nombres (int, char, long, double, ...). Quand tu retournes une variable locale de type nombre, tu n'as aucun problème. Là, c'est pareil. Ce qui sort, c'est une copie de la variable locale (il y a des cas particuliers d'optimisations possibles qui vont économiner une copie).
    Quand tu écris
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int i = 42;
    int j = 2;
    j= i;
    La dernière affectation écrase l'ancienne valeur de j. Il n'y a pas de problème. Avec les std::string, c'est pareil. Tu as une sémantique de valeur. Et la mémoire est gérée de ménière transparente pour toi.

    PS: la gestion transparente de la mémoire est orthogonale au fait que le C++ supporte la programmation OO.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  4. #4
    Membre chevronné Avatar de themadmax
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    446
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 446
    Par défaut
    Je te conseille aussi l'utilisation de std::string, mais si tu est obligé de t'en passé il est plus sage que l'appelant passe le buffer de chaine et sa taille.
    ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    bool catfunc(char* buff, int size, const char txt1, const char txt2)
    {
       if ( buff == NULL )
          return false; //Pourquoi pas lever une exeception ?
       strcat( buff, txt1 ); //voir strcat_s sous VC++
       strcat( buff, txt2 ); //sinon geré un debordement possible
       return true;
    }
    char buff[255];
    catfun( buff, 255, "text1", "text2" ); //on devrai tester le retour

  5. #5
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Citation Envoyé par themadmax
    mais si tu est obligé de temp passé il est plus sage que l'appelant passe le buffer de chaine et sa taille.
    Je ne comprends pas ta phrase. Il doit manquer un mot.

    PS: Ton code a toujours un potentiel buffer overflow, et il calcule deux fois la longueur de la chaîne à mettre devant.
    PS2: pour moi, ici, c'est une assertion qui convient le mieux. Car passer 0 à la chaîne destination n'a aucun intérêt. Il ne peut que s'agir d'une erreur de programmation => assert.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  6. #6
    Membre émérite Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Par défaut
    Citation Envoyé par Luc Hermitte
    Je ne comprends pas ta phrase. Il doit manquer un mot.
    Pas de mot qui manque, c'est que c'est mal écrit

    "mais si tu es obligé de t'en passer il est plus sage que l'appelant passe le buffer de chaine et sa taille."

Discussions similaires

  1. Tuto MVVM : dans le source, une property de type string retourne un booléen ?!
    Par zax-tfh dans le forum Windows Presentation Foundation
    Réponses: 5
    Dernier message: 23/03/2009, 08h35
  2. Type String* en paramètre...
    Par Invité dans le forum MFC
    Réponses: 4
    Dernier message: 24/02/2004, 19h48
  3. Convertir une date en type string
    Par ziboux dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 29/10/2003, 10h52
  4. [VB6] creation de variable de type string dynamiquement
    Par da40 dans le forum VB 6 et antérieur
    Réponses: 10
    Dernier message: 12/06/2003, 16h59
  5. Réponses: 2
    Dernier message: 05/06/2002, 12h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo