Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 12 sur 12
  1. #1
    Candidat au titre de Membre du Club
    Inscrit en
    avril 2011
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : avril 2011
    Messages : 93
    Points : 10
    Points
    10

    Par défaut Erreur sémantique lors de la concaténation de deux chaines de caractères

    Bonjour à tous,

    J'ai pour les cours à expliquer le fonctionnement d'un bout de code, j'en comprend bien le sens mais j'ai une erreur alors que je ne devrais pas en avoir.

    La ligne qui fait planter le programme est la ligne, je ne comprends pas pourquoi :/
    Code :
    memmove (dest+ l_dest, ajout, nb_carac_max - l_dest);
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    int main()
    {
        char tab1[10] = "Coucou, ";
        char tab2[40] = "tu veux voir ma paire de lunette ?";
    // On créé deux tableau et l'on va concaténer le premier au second.
        concat(tab1,tab2,70);
        cout<< tab1;
    // On affiche la concaténation du tableau 1
        return(0);
    }
     
    /*Fonction cacaténer
    Elle permet de concaténer une chaîne de caractère 2 à une chaine de caractère 1 afin d'obtenir un seul tableau.
    */
     
    char* concat(char *dest, const char *ajout, int nb_carac_max)
    {
        int l_dest= strlen(dest);
        int l_ajout= strlen(ajout);
     
        if( nb_carac_max <= 0 || nb_carac_max > l_dest + l_ajout)
        {
            nb_carac_max= l_dest+ l_ajout;
        }
     
        if( nb_carac_max > l_dest)
        {
            memmove (dest+ l_dest, ajout, nb_carac_max - l_dest);
        }
        dest[nb_carac_max] = '\0';
        return dest;
    }
    Questions :
    Pour le prof écrit "return dest;" et non pas "return (dest);" ?

  2. #2
    Membre habitué
    Inscrit en
    mars 2010
    Messages
    118
    Détails du profil
    Informations forums :
    Inscription : mars 2010
    Messages : 118
    Points : 119
    Points
    119

    Par défaut

    Ton tableau tab1 n'a pas une taille suffisante pour la concaténation, utiliser memmove dans un tel cas ne peut que conduire à des Undefined Behavior.

  3. #3
    Membre expérimenté Avatar de Flob91
    Profil pro Florent
    Ingénieur
    Inscrit en
    mai 2005
    Messages
    810
    Détails du profil
    Informations personnelles :
    Nom : Florent
    Âge : 30
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Industrie

    Informations forums :
    Inscription : mai 2005
    Messages : 810
    Points : 549
    Points
    549

    Par défaut

    Salut,

    Le probleme du plantage est que ton tableau de destination n'est alloué que pour 10 caractères.

    Ensuite, le

    est exactement pareil que :

    Juste que ca enleve toute ambigüité.

  4. #4
    Candidat au titre de Membre du Club
    Inscrit en
    avril 2011
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : avril 2011
    Messages : 93
    Points : 10
    Points
    10

    Par défaut

    Super
    Merci beaucoup, je me disais que cela provenait de la taille du tableau, mais je pensais naïvement que celui-ci s'agrandissait automatiquement ^^
    Résolu

  5. #5
    Candidat au titre de Membre du Club
    Inscrit en
    avril 2011
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : avril 2011
    Messages : 93
    Points : 10
    Points
    10

    Par défaut

    Dernière question ^^

    Quel est l'intérêt du return dans cette fonction ?

  6. #6
    Membre expérimenté Avatar de Flob91
    Profil pro Florent
    Ingénieur
    Inscrit en
    mai 2005
    Messages
    810
    Détails du profil
    Informations personnelles :
    Nom : Florent
    Âge : 30
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Industrie

    Informations forums :
    Inscription : mai 2005
    Messages : 810
    Points : 549
    Points
    549

    Par défaut

    Cela permet de retourner le pointeur de la chaine de caractères résultant de la concaténation

  7. #7
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 003
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 003
    Points : 5 170
    Points
    5 170

    Par défaut

    Juste par curiosité: c'est un cours de C ou un cours de C++?

  8. #8
    Expert Confirmé
    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    1 453
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 1 453
    Points : 3 114
    Points
    3 114

    Par défaut

    Comme d'habitude, du "C avec iostream"…

    Ce que je déteste les profs qui agissent ainsi.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

  9. #9
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 003
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 003
    Points : 5 170
    Points
    5 170

    Par défaut

    J'ose espérer que le but de ce cours avec des char[] et des char* est de, par la suite, montrer les avantages des std::string

  10. #10
    Candidat au titre de Membre du Club
    Inscrit en
    avril 2011
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : avril 2011
    Messages : 93
    Points : 10
    Points
    10

    Par défaut

    J'ose espérer que le but de ce cours avec des char[] et des char* est de, par la suite, montrer les avantages des std::string
    Et tu as tout à fait raison mon ami, le prof nous a demandé ensuite de le comparer avec une fonction identique mais totalement en C++ (utilisation de .size(), du type string, de la concaténation directe de deux chaines de caractère en string).

    Autres questions donc, en comparer le code initial en C

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    char* concat(char *dest, const char *ajout, int nb_carac_max)
    {
        int l_dest= strlen(dest);
        int l_ajout= strlen(ajout);
     
        if( nb_carac_max <= 0 || nb_carac_max > l_dest + l_ajout)
        {
            nb_carac_max= l_dest+ l_ajout;
        }
     
        if( nb_carac_max > l_dest)
        {
            memmove (dest+ l_dest, ajout, nb_carac_max - l_dest);
        }
        dest[nb_carac_max] = '\0';
        return dest;
    }
    Avec celui en C++

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    string& concat_string(string& dest, const string& ajout, int nb_carac_max)
    {
        int l_dest= dest.size(), l_ajout= ajout.size();
     
        if (nb_carac_max <=0 || nb_carac_max > l_dest+ l_ajout)
        {
            dest = dest + ajout;
        }
        else
            if(nb_carac_max> l_dest)
            {
                dest= dest.substr(0,nb_carac_max - l_dest);
            }
            else if( nb_carac_max < l_dest)
            {
                dest = dest.substr(0,nb_carac_max);
            }
        return (dest);
    }
    Il a posé 4 questions :

    1) Quelles sont les différences ?

    2) Pourquoi la version en C++ est-elle plus facilement maintenable ?

    3) Est-ce que l'utilisation de nb_carac_max est toujours justifié ?

    4) Est ce que le code fonctionne et que fait-il ?
    Code :
    concat_string(tab1,tab2)= concat_string(tab1,tab2)+ tab1;
    Que pensez-vous de ma réponse ?
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /* Explications
    1)  Les différences :
        - la récupération de la taille de la chaîne de caractère se fait grâce à .size() alors qu'en C on utilise strlen();
        - la concaténation se fait par dest+ajout au lieu d'utiliser la fonction memmove en C.
        - la fonction permet .substr permet de tronquer la partie d'une chaîne de caractère.
     
    2) C'est la version en c++ qui est la plus facilement utilisable et maintenable car il n'y a pas de contrainte liée à la taille du tableau d'origine
    contrairement à la version en C.
     
    3) Oui l'utilisation de nb_carac_max est toujours justifié, dans le cas ou l'utilisateur entre une valeur négative, elle permet également
    de choisir le nombre de caractère qu'il souhaite récupérer en retour.
     
    4) Oui le code est correcte, on concatène deux chaîne de caractère (tab1 concaténé avec tab2) + tab1 qui est(tab1 concaténé avec tab2).
    Ce qui éguivant à transformer tab1 en tab1 modifié +tab1 modifié.
    Cela est possible car la fonction concat_string renvoit un string, et l'on peut concactèner deux string entre eux avec l'opérateur +.
    */

  11. #11
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 661
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 661
    Points : 15 973
    Points
    15 973

    Par défaut

    Salut,

    En fait, dans le code C++, il y a les trois quart des lignes (en fait, 18/19 des lignes ) qui ne servent strictement à rien

    Franchement, je me demande quelle sera la prochaine étape du prof
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  12. #12
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro Loïc Joly
    Développeur informatique
    Inscrit en
    août 2004
    Messages
    4 872
    Détails du profil
    Informations personnelles :
    Nom : Homme Loïc Joly
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : août 2004
    Messages : 4 872
    Points : 10 713
    Points
    10 713

    Par défaut

    Le jour où je vois du vrai code C++ écrit ainsi, je demande à son responsable de le réécrire

    Du coup, j'ai du mal pour les réponses à tes questions, j'ai l'impression qu'elles sont à apprécier dans une certain contexte que l'on n'a pas. Je vais donner mon avis, mais qui est 100% subjectif.

    1/ Il y a plein de différences de syntaxe, bien entendu. On évite de devoir parcourir les chaînes pour en calculer la longueur. Il y a une partie de l'algorithme qui ne marche pas : dest.substr(0,nb_carac_max - l_dest); : Si l_dest vaut 1, et nb_carac_max vaut 10, on va récupérer les 9 premiers caractères d'une chaîne qui en contient 1... Ca ne va pas planter, car le C++ est bien fait, mais je ne vois vraiment pas le but..

    2/ Telle qu'écrite, j'ai du mal à dire si elle est plus aisément maintenable, puisque je n'ai aucune idée de ce qu'elle est sensée faire . Le seul avantage que j'y vois c'est que quoi qu'il arrive, elle produira un résultat sans avoir corrompu la mémoire, même si je ne comprends pas la nature de ce résultat. La version C peut corrompre la mémoire si l'utilisateur se plante dans sa gestion de buffers

    3/ Non, absolument pas ! Une fonction de concaténation doit concaténer, et rien d'autre. Si l'utilisateur veut réduire la taille finale après concaténation, qu'il le fasse explicitement. Mais cette réduction ne fait pas partie de la notion de concaténation, et n'a rien à y faire. Le fait qu'elle apparaisse dans la version C est une limite du langage, qui ne permet pas de gérer les chaînes de caractères et oblige son utilisateur à se focaliser sur des détails bas niveau qui viennent perturber la clarté du code.
    Si on a vraiment besoin d'une fonction qui concatène en tronquant, sans utiliser plus de mémoire que nécessaire, alors, pourquoi pas, mais il ne faut pas l'appeler concat.

    4/ Ce code ne fonctionne pas : On modifie plusieurs fois la même variable à l'intérieur d'une même expression (sans qu'il y ait de point de séquence, pour être plus précis), ce qui n'est pas autorisé. C'est comme si on écrivait int a = i++ + i++;
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Et celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++

+ Répondre à la discussion
Cette discussion est résolue.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •