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 :

modifier une chaîne de caractères dans une fonction void


Sujet :

C

  1. #1
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2012
    Messages : 26
    Points : 17
    Points
    17
    Par défaut modifier une chaîne de caractères dans une fonction void
    Bonjour à tous, et bonne année à tous.

    Je m'adresse à vous car j'ai un petit souci avec une fonction, voici d'abord une version de ma fonction qui marche très bien et qui fait ce j'attend d'elle, c'est-à-dire supprimer les doublons dans une chaîne de caractère passée en paramètre un peu comme l'outil "tr" sous linux, donc si par exemple je lu donne la chaîne "bonne annnee" elle me renvoie "bone ane":

    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    char* SupprimerDoublon(char *chaine, char lettre)
    {
        char *tab = malloc(sizeof(char) * strlen(chaine));
     
        if(!tab) exit(-1);
     
        int i = 0, j = 0;
     
        while(chaine[i] != '\0')
        {
            if(chaine[i] == lettre)
            {
                tab[j] = chaine[i];     
     
                for(;chaine[i] == lettre; i++);
                j++;
            }
            else
            {
                tab[j] = chaine[i];
                i++; j++;
            }
        }
     
        tab[j] = '\0';
     
        return tab;
    }
    Mais je dois appeler cette fonction de cette façon:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    char *maChaine[] = {"bonjof gbbffgw fdgfwggf wdfggdfgggggdffggff wdxur al",
                            "bbonne annee a tous",
                            "superbbe biien mon ammi"};
        int i, j;
     
        for(i = 0; i < 3; i++)
            maChaine[i] = SupprimerDoublon(maChaine[i], 'n');
     
     
        for(j = 0; j < 3; j++)
        {
            printf("%s\n", maChaine[j]);
            free(maChaine[j]);
        }
    et j'ai donc décidé de la modifier en (void) pour pouvoir l'appeler simplement comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        for(i = 0; i < 3; i++)
                 SupprimerDoublon(maChaine[i], 'n');
    Et c'est là que les problème commencent, voici mon code qui donne une segmentation fault à la ligne .

    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    void SupprimerDoublon(char *chaine, char lettre)
    {
        char *tab = malloc(sizeof(char) * strlen(chaine));
     
        if(!tab) exit(-1);
     
        int i = 0, j = 0;
     
        while(chaine[i] != '\0')
        {
            if(chaine[i] == lettre)
            {
                tab[j] = chaine[i];  
     
                for(;chaine[i] == lettre; i++);
                j++;
            }
            else
            {
                tab[j] = chaine[i];
                i++; j++;
            }
        }
     
        tab[j] = '\0';
     
        strcpy(chaine, tab);
    }
    Donc je me pose des questions, et je ne comprend pas pourquoi ça ne marche pas, sachant que dans le main je l'appelle de cette façon:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    char *maChaine[] = {"bonjof gbbffgw fdgfwggf wdfggdfgggggdffggff wdxur al",
                            "bbonne annee a tous",
                            "superbbe biien mon ammi"};
        int i, j;
     
        for(i = 0; i < 3; i++)
            SupprimerDoublon(maChaine[i], 'n');
     
     
        for(j = 0; j < 3; j++)
        {
            printf("%s\n", maChaine[j]);
        }
    J'ai un petit doute sur le fait que j'alloue dynamiquement le tab mais pas la chaine qui arrive dans la fonction mais mes tests ne sont pas concluant. Pouvez-vous m'éclairer ?

    Merci à vous.

  2. #2
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    C'est vrai que c'est à cause de la nature de la chaine passée en argument à la fonction : elle est allouée dans une zone mémoire non modifiable et du coup le strcpy() plante.

    Il faut savoir que si on écrit
    la chaine "abcde" ne doit pas être modifiée et son adresse est placée dans tab. On préfère écrire par prudence
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const char * tab = "abcde";
    Par contre avec
    la chaine "abcde" INITIALISE le tableau tab qui peut parfaitement être modifié.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  3. #3
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2012
    Messages : 26
    Points : 17
    Points
    17
    Par défaut
    Ok, j'ai compris mon erreur, ça marche maintenant. Merci beaucoup.

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Attention, dans l'état actuel ta fonction SupprimerDoublon contient une fuite de mémoire.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2012
    Messages : 26
    Points : 17
    Points
    17
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Attention, dans l'état actuel ta fonction SupprimerDoublon contient une fuite de mémoire.
    Bonjour, et merci de ta réponse , je t'avouerai que je n'ai pas encore compris / appris ce qu'était vraiment une "fuite de mémoire", donc je ne peux pas vraiment comprendre ce que tu me dis. Par contre, si par "fuite de mémoire" tu veux dire que j'ai oublié de libérer tab dans ma fonction, alrs je comprends de quoi tu parles. Je l'avais viré pour tester quand ça ne marchait pas, mais depuis j'ai bien rajouté:

    juste après le:

    à la fin de ma fonction. Est-ce cela ? Sinon je me suis un peu planté dans la description et je pense que vous l'aviez remarqué, elle ne supprime pas les doublons mais la répetition d'un caractère.

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    je t'avouerai que je n'ai pas encore compris / appris ce qu'était vraiment une "fuite de mémoire", donc je ne peux pas vraiment comprendre ce que tu me dis. Par contre, si par "fuite de mémoire" tu veux dire que j'ai oublié de libérer tab dans ma fonction
    Tu sais donc ce qu'est une fuite mémoire

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 984
    Points
    30 984
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par jujudelyon Voir le message
    Bonjour, et merci de ta réponse , je t'avouerai que je n'ai pas encore compris / appris ce qu'était vraiment une "fuite de mémoire"
    Bonjour
    Quand tu demandes de la mémoire (avec malloc) elle t'est donnée par l'OS.
    Si tu ne la libères pas mais que ton programme se termine, elle va "on ne sait où". Donc là on parle (en image) de "fuite mémoire".
    Sur certains OS, elle est alors récupérée par l'OS et tout va bien (ou plus prosaïquement l'OS rattrappe la connerie). Sur d'autres il ne la récupère pas et faut alors rebooter ta machine pour retrouver ta pleine capacité RAM.

    PS: évite les "exit()" impromptus en cas d'échec d'une ressource. On ne sort pas d'une fonction par exit mais on renvoie le pb à l'appelant qui pourra alors prendre une décision...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Dans tous les cas, même quand elle est "récupérée par l'OS", cela n'arrive qu'à la fin du programme. Donc, si tu as une "fuite de mémoire" dans un programme qui tourne en permanence (comme un serveur, ou un truc qu'on laisse en arrière-plan comme Skype), la mémoire reste "perdue" jusqu'à arrêt de l'ordinateur.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2012
    Messages : 26
    Points : 17
    Points
    17
    Par défaut
    D'accord, c'est une
    bonne chose d'avoir plusieurs avis sur la question. Mais est-ce qu'une fuite de mémoire se résume seulement à l'oublie de libérer une ressource ?

    Sinon, une bonne pratique serait alors de toujours ajouter le mot clé "const" devant une chaine déclarée avec une * ?
    Edit: après un petit test je vois que gcc me signal que je ne peux pas modifier la chaine quand j'ajoute const, alors que sans const il ne me dit rien. Vendu.

    PS: évite les "exit()" impromptus en cas d'échec d'une ressource. On ne sort pas d'une fonction par exit mais on renvoie le pb à l'appelant qui pourra alors prendre une décision...
    Hier 08h06
    Je cherchais justement comment faire une gestion des erreurs propre en C. Ma fonction est de type void, elle ne retourne donc aucune valeur, et quand bien même elle retournerait une valeur et qu'en cas d'erreur j'arrive à rendre la main à mon main(), j'ai un nouveau problème. Si je lui demande pas de quitter en cas de plantage qu'est-ce que je peux lui faire faire ? Je suppose que dans un grand programme on peut passer à autre chose, mais je n'ai qu'une fonction.

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 690
    Points : 30 984
    Points
    30 984
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par jujudelyon Voir le message
    D'accord, c'est une
    bonne chose d'avoir plusieurs avis sur la question. Mais est-ce qu'une fuite de mémoire se résume seulement à l'oublie de libérer une ressource ?
    Pour ce que j'en sais... oui.

    Citation Envoyé par jujudelyon Voir le message
    Sinon, une bonne pratique serait alors de toujours ajouter le mot clé "const" devant une chaine déclarée avec une * ?
    Une bonne pratique serait de mettre const de partout... puis de l'enlever seulement si c'est nécessaire...

    Citation Envoyé par jujudelyon Voir le message
    Je cherchais justement comment faire une gestion des erreurs propre en C. Ma fonction est de type void, elle ne retourne donc aucune valeur, et quand bien même elle retournerait une valeur et qu'en cas d'erreur j'arrive à rendre la main à mon main(), j'ai un nouveau problème. Si je lui demande pas de quitter en cas de plantage qu'est-ce que je peux lui faire faire ? Je suppose que dans un grand programme on peut passer à autre chose, mais je n'ai qu'une fonction.
    Attention, je n'ai pas dit de ne pas quitter... J'ai dit de ne pas quitter depuis une fonction (sous-entendu "autre que le main") !

    Le principe est que chaque fonction "critique" renvoie une valeur spéciale si elle n'arrive pas à faire son travail. Corollairement elle renverra une autre valeur spéciale mais différente quand le travail est fait. Généralement on privilégie le NULL quand il y a un soucis et le paramètre reçu quand il n'y en a pas.
    Ensuite, la fonction appelante récupère (et éventuellement teste) la valeur renvoyée. Si celle-ci indique que la fonction appelée n'a pas réussi son travail, cela peut alors devenir un état critique à la fonction appelante. Donc elle-aussi, dans ce cas là, renverra une valeur spéciale à sa propre fonction appelante. Et etc etc.
    Fatalement, si toute la pile des appels renvoie le pb à l'appelant, cela arrive au main(). Lui il est spécial dans le sens que c'est la fonction principale. Elle elle n'a donc plus le choix. Si tout ce qui a été appelé a échoué, ben malheureusement elle elle ne peut que quitter le programme. Toutefois elle peut le faire via exit() ou (mieux) via return.

    Exemple
    Code c : 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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    char *supprime_doublon(char *chaine)
    {
        char *work;
        if ((work=malloc((strlen(chaine) + 1) * sizeof(char))) == NULL)
            return NULL;
     
        ... (travail...)
        free(work);
     
        // Renvoi valeur spéciale: bon ben tant qu'à faire autant renvoyer chaine
        return chaine;
    }
     
    char **travail_texte(char *texte[])
    {
        char **pt;
        for (pt=texte; *pt; pt++)
        { 
            if (supprime_doublon(*pt) == NULL)
            {
                  // Oups, problème - Peut-être peut-on faire autrement... non tant pis
                 return NULL;
            }
        }
     
        // Tout s'est bien passé
        return pt;
    }
     
    int main(int argc, char *argv[])
    {
          if (travail_texte(argv + 1) == NULL)
          {
                // Ok, la première fonction échoue, on ne peut plus rien faire
                return -1;
           }
     
          ....
          // Fin du programme
          return 0;
    }

    C'est parfois fastidieux. Parce que programmer une alternative implique ensuite de prendre en compte cette alternative. Alors pour les petits jeux, les petits codes persos poubellisables 3 jours après avoir été utilisés ça passe mais pour des applis vraiment importante, il faut le faire. Ne serait-ce que pour éviter le message "ce programme a cessé de fonctionner, Windows cherche une solution à ce problème"...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  11. #11
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2012
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2012
    Messages : 26
    Points : 17
    Points
    17
    Par défaut
    Ok, merci pour toutes ces explications, je vais tâcher de tenir compte de vos conseils. Merci beaucoup.

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 05/11/2014, 12h55
  2. [MySQL] Remplacer une chaîne de caractères dans une base de données
    Par Furius dans le forum PHP & Base de données
    Réponses: 10
    Dernier message: 27/11/2013, 21h06
  3. Réponses: 7
    Dernier message: 14/12/2005, 09h53
  4. Remplacer une chaîne de caractères dans une base
    Par Furius dans le forum Requêtes
    Réponses: 4
    Dernier message: 19/10/2005, 23h03
  5. Réponses: 3
    Dernier message: 09/05/2002, 01h39

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