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 :

Corruption de char


Sujet :

C

  1. #1
    Membre à l'essai
    Inscrit en
    Mai 2012
    Messages
    19
    Détails du profil
    Informations forums :
    Inscription : Mai 2012
    Messages : 19
    Points : 11
    Points
    11
    Par défaut Corruption de char
    Bonjour

    Quelqu'un peut -il m"expliquer mon erreur

    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
     
    char*  self_filename()
        {
            char self_filename[MAX_PATH];
            GetModuleFileName(NULL,self_filename,MAX_PATH);
     
            return self_filename;
        }
     
    void main()
        {
                char* nom_origine ;
                nom_origine = self_filename();
                printf("%s\r\n",nom_origine);  //CORRUPTED
     
                printf("%s\r\n",self_filename());  //OK
     
        }
    Ma variable nom_origine est tronquée, elle est finie par %$$

    Merci

  2. #2
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 882
    Points
    7 882
    Par défaut
    La variable retournée par self_filename est locale à cette fonction, donc invalide en dehors de cette dernière.

    Il faut stocker sa valeur dans quelque chose de plus persistant (malloc, static, ...).
    ɹǝsn *sıɹɐlos*

  3. #3
    Membre à l'essai
    Inscrit en
    Mai 2012
    Messages
    19
    Détails du profil
    Informations forums :
    Inscription : Mai 2012
    Messages : 19
    Points : 11
    Points
    11
    Par défaut
    MErci !!

    J'ai fait ça et c'est bon

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    char*  self_filename()
        {
            static char self_filename[MAX_PATH];
            GetModuleFileName(NULL,self_filename,MAX_PATH);
     
            return self_filename;
        }
    POurquoi c'était pas logique pour moi le fait que la variable soit locale à la fonction ?
    C'est une particularité du c je suppose ? car php m'a habitué autrement !

  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 518
    Points
    41 518
    Par défaut
    Le problème n'est pas de retourner une variable locale, mais un pointeur vers une variable locale non-static (ici, un pointeur vers le premier caractère d'un tableau local).

    Le seul moyen de transmettre un tableau "par valeur", c'est le mettre dans une structure. Comme ça n’accommode pas les problèmes de taille variable, à la place on utilise la solution de retourner l'adresse d'un tableau alloué dynamiquement.
    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
    Inscrit en
    Mai 2012
    Messages
    19
    Détails du profil
    Informations forums :
    Inscription : Mai 2012
    Messages : 19
    Points : 11
    Points
    11
    Par défaut
    zut j'ai rien compris

  6. #6
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    En c, la mémoire n'est pas "persistante".
    Lorsque tu déclare une variable dans une fonction, le système va allouer de la mémoire pour celle-ci.
    Une chaine de caractère (char*) est une variable de type pointeur.
    Un pointeur est une variable qui contient l'addresse de départ de ta chaine de caractère.
    Petit exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    // bobby est une chaine de caractere donc de type char*
    char bobby[155];
    //Equivalent à char* bobby = malloc(155);
    Sur ce bout de code il faut comprendre:
    Donne moi une addresse dans la RAM avec 155 block de la taille d'un char allouer derriere.
    Maintenant si tu fais comme ça:

    Alors le système va allouer une partie de ta mémoire de manière à contenir la chaine de caractère "chaine\0" donc va allouer 7char.

    Ta variable bobby va pointer sur une zone mémoire de 7char.

    Maintenant lorsque tu effectues une allocation de cette manière, le système va réservé cet espace que pendant la fonction, une fois sortie de cette fonction, cet espace mémoire est désallouer, et les valeurs des octets ne sont plus assurer (cet espace n'appartient plus à ta variable).

    Lorsque tu retourne bobby, tu retourne non pas une chaine de caractere mais le pointeur vers cette zone mémoire.
    Il est donc normal que lorsque tu accède à cette mémoire, les données présentes ne sont plus tel qu'elles l'étaient dans la fonction.

    Le mot clé static définis:
    La porté de cette variable ne s'arrète pas à la fonction, l'allocation de la mémoire dois donc être définitive et partager pour tout le programme.

    Ainsi, lorsque tu retourne ton pointeur, la mémoire est toujours allouée et les valeurs des octets restent inchangée.

    Pour mieux comprendre, imagines-toi que la mémoire est une énorme armoire, composé de tiroirs eux-même composé de case.
    Lorsque tu déclare une variable, tu poses une petite étiquette sur un tiroir avec le nom de ta variable (c'est l'allocation). Tant que l'étiquette est présente, personne ne peut ouvrir le tiroir pour le modifier hormis celui possédant la clef (la variable sur l'etiquette). Une fois sortis de ta fonction, si le mot clef statique ou si tu n'as pas allouer la mémoire avec un malloc, l'intendant de ton armoire va aller supprimer toute les étiquettes des tiroirs qui ont été apposé pendant la fonction. N'importe qui peut donc ouvrir le tiroir et modifier les objets à l'intérieur.

    J'espère avoir été clair, et merci d'avoir lu ce long pavé .
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  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 684
    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 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par networkinfo Voir le message
    POurquoi c'était pas logique pour moi le fait que la variable soit locale à la fonction ?
    C'est une particularité du c je suppose ? car php m'a habitué autrement !
    Salut
    C'est une particularité de tous les langages structurés. Et c'est aussi le cas même pour php. Car en php, une variable "$i" située dans une fonction ne sera pas utilisable en dehors (ou alors php a bien changé).

    La différence c'est que pour php ainsi que pour les autres langages de plus haut niveau que le C, les chaines sont des entités manipulables. Donc ton code aurait fonctionné dans php parce que le return de la string aurait renvoyé toute la string vers l'appelant.
    Or le C ne sait pas manipuler une chaine (dans le sens "prendre la chaine dans son intégralité pour par exemple la comparer avec une autre"). Il ne sait manipuler que ses caractères un à un (et leurs adresses). Donc, en C, quand tu renvoie une string tu ne renvoies en fait que l'adresse de la zone où elle commence. Mais si cette zone disparait ensuite, tu te retrouves avec une adresse inutilisable.
    Ceci dit, mettre en static peut paraitre une bonne idée et fonctionnera dans la plupart des cas car la zone ne disparait pas lorsque la fonction se termine. Le seul danger de cette procédure sera dans le cas où tu es en multithread et où, malheureusement, ta fonction sera appelée par deux threads en même temps. Car en static tu n'as qu'une seule zone mémoire. Et si les deux threads y écrivent en même temps...
    Tu auras aussi un soucis avec static si tu t'en sers pour mémoriser l'état de ta fonction en la quittant pour le réutiliser à ton retour (comme le fait strtok()). Ca fonctionnera jusqu'au jour où tu utiliseras ta fonction dans des contextes différents. Par exemple dans deux boucles imbriquées avec utilisation dans la boucle supérieure et utilisation dans la boucle inférieure. Dans ce cas, à l'itération suivante de la boucle supérieure tu utiliseras l'état mémorisé par la dernière itération de la boucle inférieure...

    En C, la solution la plus viable est que ta zone soit définie dans la fonction appelante et qu'elle soit passée comme paramètre à self_filename(). Cette dernière la remplit puis disparait mais la zone, venant "du dehors", persiste et reste utilisable par l'appelant. C'est d'ailleurs ainsi que fonctionne GetModuleFileName que tu utilises...
    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 518
    Points
    41 518
    Par défaut
    @skeud: Les chaînes littérales sont statiques!
    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
    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
    @skeud : ton explication contient malheureusement plusieurs choses fausses ou approximatives !

    Le premier problème est que tu ne fais pas la différence entre tas, pile et mémoire constante. En C, il y a plusieurs types de mémoires.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     // bobby est une chaine de caractere donc de type char*
    char bobby[155];
    //Equivalent à char* bobby = malloc(155);
    C'est faux. bobby est de type char[155] et non un char*. C'est un tableau, non pas un pointeur. Ce n'est pas équivalent à ce qui est en commentaire car ce qui est en commentaire utilise le tas alors qu'un tableau est en allocation automatique sur la pile.

    char* bobby="chaine";Alors le système va allouer une partie de ta mémoire de manière à contenir la chaine de caractère "chaine\0" donc va allouer 7char.
    Il va effectivement allouer de la mémoire, mais dans la mémoire constante. Cette zone sera toujours valable, pendant toute l'exécution du programme. Mais tu devrais d'ailleurs écrire const char* bobby="chaine"; car c'est bien des données constantes. Tu as le droit de renvoyer un tel pointeur.

    La porté de cette variable ne s'arrète pas à la fonction, l'allocation de la mémoire dois donc être définitive et partager pour tout le programme.
    Il ne faut pas confondre portée (qui est la visibilité : une variable statique à une fonction n'est visible que dans cette fonction) et type d'allocation. Une telle variable ne sera pas en allocation automatique donc ne sera pas sur la pile (mais je ne sais plus où elle sera...peut-être le tas) et donc la zone mémoire ne sera pas réutilisée en sortie de la fonction. Renvoyer un pointeur vers une telle zone est donc valide.

    PS : la RAM est toujours non persistante, je pense que tu voulais plutôt dire "réutilisable".


    @networkinfo :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    char*  self_filename()
        {
            static char self_filename[MAX_PATH];
            GetModuleFileName(NULL,self_filename,MAX_PATH);
     
            return self_filename;
        }
    Je pense qu'ici, tu devrais plutôt utiliser malloc(). Ou alors il faut que tu sois bien conscient de ce que static implique. Imagine que tu appelles une 1ere fois la fonction et récupères p1. Tu rappelles une nouvelle fois la fonction, la variable statique est mise à jour et tu récupères p2. p1 et p2 pointe sur la même zone. Donc la personne qui utilise p1 verra ses données mise à jour. Si c'est ce que tu souhaites faire, static est fait pour toi. Sinon, malloc() sera ton ami.

  10. #10
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 882
    Points
    7 882
    Par défaut
    Si la valeur retournée par GetModuleFileName peut changer et/ou si on veut la modifier par la suite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    char *self_filename()
    {
      char self_filename[MAX_PATH];
      GetModuleFileName(NULL,self_filename,MAX_PATH);
      return strdup(self_filename); /* ne pas oublier de faire un free() si appels récurrents pour éviter les fuites mémoire */
    }
    Si la valeur retournée par GetModuleFileName est toujours la même et qu'on ne la manipule pas par la suite.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    char *self_filename()
    {
      static char self_filename[MAX_PATH];
      if(self_filename[0]==0) GetModuleFileName(NULL,self_filename,MAX_PATH);
      return self_filename;
    }
    ɹǝsn *sıɹɐlos*

  11. #11
    Membre à l'essai
    Inscrit en
    Mai 2012
    Messages
    19
    Détails du profil
    Informations forums :
    Inscription : Mai 2012
    Messages : 19
    Points : 11
    Points
    11
    Par défaut
    D'abord merci à tous !
    Je vais le relire pour m'en imprégnier

    Si cette variable n'est pas amenée à changer, ne devrais-je pas la stocker en globale pour m'en resservir plus tard dans mon code ??

  12. #12
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 882
    Points
    7 882
    Par défaut
    Si c'est en effet une constante, ça peut être une variable globale mais dans ce cas, il ne faut pas oublier de l'affecter une première fois quelque part.

    Mettre la logique dans une fonction avec un stockage statique est plus simple et plus flexible.
    ɹǝsn *sıɹɐlos*

  13. #13
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    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 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par networkinfo Voir le message
    Si cette variable n'est pas amenée à changer, ne devrais-je pas la stocker en globale pour m'en resservir plus tard dans mon code ??
    Il faut essayer d'éviter les globales autant que possible. Si cette variable n'est pas amenée à changer (sous-entendu "après son initialisation") alors autant l'initialiser dans le main() (après-tout, c'est le rôle de cette fonction...) puis la faire passer en tant que paramètre aux fonctions qui en auront besoin...

    Là où ça peut devenir plus compliqué, c'est si tu commences à avoir 2, 3, 10, 20 variables de cette nature (ça peut arriver avec de gros projets). En suivant cette logique, tes fonctions auront 2, 3, 10, 20 paramètres et ce sera franchement illisible.
    Dans ce cas, une solution intéressante est de définir une structure dédiée aux éléments "généraux" de ton programme. Ensuite, te suffit de passer cette structure aux fonctions qui en ont besoin. Quel que soit le nombre d'éléments à gérer, tu n'auras qu'un seul paramètre à passer aux fonctions. Mais ces fonction auront quand-même accès à l'ensemble des éléments généraux de ton programme...
    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
    typedef struct {
        char self_filename[MAX_PATH];
        double param1;
        int param2;
        char infoX;
        float infoY;
    } t_config;
     
    int main()
    {
        t_config config;
        ...
        self_filename(&config);
        game_param(&config);
        ...
    }
     
    void self_filename(t_config *conf)
    {
        GetModuleFileName(NULL, conf->filename, MAX_PATH);
    }
     
    void game_param(t_config *conf)
    {
        conf->param1=...
        conf->param2=...
        ...
    }
    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]

Discussions similaires

  1. Réponses: 3
    Dernier message: 02/07/2003, 16h24
  2. Char(x) -> chaine concaténée d'espaces ?
    Par rgz dans le forum Débuter
    Réponses: 7
    Dernier message: 27/06/2003, 11h59
  3. [PostgreSql] Problème de cadreage de char !!!
    Par moipastoi dans le forum Requêtes
    Réponses: 3
    Dernier message: 08/05/2003, 18h01
  4. Réponses: 6
    Dernier message: 24/03/2003, 17h11
  5. Traitement d'un char* renvoyé par une DLL en C++
    Par LuluTchab dans le forum Langage
    Réponses: 4
    Dernier message: 22/03/2003, 21h48

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