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 :

Mes pointeurs se font écraser ???


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    95
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 95
    Points : 42
    Points
    42
    Par défaut Mes pointeurs se font écraser ???
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Noms * liste_personne[32];
    Vaut-il mieux faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Noms
    {
         char * m_nom[32];
         ...
         void SetNom(int i, char * nom)
         {
               m_nom[i] = (char*)malloc(_tcslen(nom) * sizeof(char));
               sprintf(m_nom[i], nom);
         }
    };
    Ou plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class Noms
    {
         char * m_nom[32];
         ...
         void SetNom(int i, char * nom)
         {
               m_nom[i] = nom;
         }
    };
    Dans la première solution, j'ai des raisons de penser qu'au fur et à mesure que l'on créé les personnes et que l'on rempli les noms dynamiquement, il est possible que l'allocation empiète sur les pointeurs (c possible ça ?). C'est la seule explication que j'ai. Ainsi, lorsque je fait:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    liste_personne[0] = new Noms();
    liste_personne[0]->SetNom(0, "toto");
    liste_personne[0]->SetNom(1, "tata");
    ...
     
    liste_personne[1] = new Noms();
    liste_personne[1]->SetNom(0, "titi");
    liste_personne[1]->SetNom(1, "tutu");
    ...
    L'appel des méthodes SetNom() semble allouer de la mémoire sur laquelle est le pointeur vers liste_personne suivant (liste_personne[1] ici puis les autres...), et donc j'obtiens un zoli plantage.

    Dans la 2ème solution (classe), faire pointer mes pointeurs directement vers les chaines passées en paramètres ne semble pas très "propres" puisque qu'il s'agit (a priori) de chaines de caractères temporaires (je pense) qui seraient donc effacées si la mémoire le decidait.

    Que faire ?

  2. #2
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    vu l'heure tardive, j'ai du mal avec les pointeurs
    Citation Envoyé par norwy
    Que faire ?
    utiliser les string et vector de la STL

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    95
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 95
    Points : 42
    Points
    42
    Par défaut
    On ne peut pas toujours passer par une autre solution et je trouve que j'évoluerais positivement en sachant au moins pourquoi la 1ère solution ne marche effectivement pas (en repassant à la 2ème ça marche à nouveau). Contourner les problèmes ne dure qu'un temps...

    J'explique le fond du problème, ce programme tourne aussi bien sur PC que sur PocketPC (d'où entre autre ma réticence à le contourner + la raison invoquée précédemment) où le type est en fait TCHAR et non pas char (on est en unicode), mais le principe est strictement le même (toutes les fonctions appelées ont leur équivalent unicode supporté par les 2 plateformes).

    La 1ère version marche dans la version PC mais pas dans la version PocketPC. Pourquoi ? Est-il possible que le peu de RAM disponible conduit à une probabilité plus grande que l'espace entre les pointeurs à la création du tableau de Noms* (liste_personne) soit si petit que l'allocation dynamique puisse déborder sur les pointeurs suivants, d'où plantage ?

    liste_personne[1] n'existerait plus alors à la suite des allocations générées par l'appel de la méthode SetNom() depuis liste_personne[0].

    J'insiste sur le fait que ce problème pourrait aussi bien être valide sur PC.
    Le problème ne se verrait pas de suite sur PC car il doit y avoir une methode qui prévoit un espace conséquent entre les pointeurs suffisant pour palier à ce problème lorsque l'allocation est petite...


    Ce que je voudrais savoir, c'est si cette explication est une pure invention de ma part (plausible puisque le problème s'est déclaré vers 2h du mat et qu'entre temps je n'ai pas beaucoup dormi ), ou si j'ai bon...


    : : :

    AVE

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Je ne vois pas en quoi le fait que le prog doivent tourner sur pocket PC soit un frein à l'utilisation de la bibliothèque standard. Ca éviterais au moins d'utiliser des fonctions non standard type stprintf ou autre. Mais bon, ce n'est pas la question.

    Je comprend mal ce que modélise la classe Noms. Est-ce un ensemble de noms, comme le suggère le pluriel ? Ou est-ce un nom unique comme le suggère la déclaration 'Noms * liste_personnes[32]' ?
    De l'implémentation, j'en déduit que Noms est une liste de chaine de caractères. Donc une liste de personnes est un tableau où chaque élément est lui même un tableau de 32 chaines de caractère. Etrange, mais passons.

    Ce qui est incompréhensible, c'est comment ton premier exemple puisse compiler.
    Dans ta méthode 'SetNom' tu affectes à 'nom' un pointeur sur une chaine de caractère.
    Ceci est impossible. La variable d'instance nom est un pointeur sur un tableau de chaînes de caractères (char * [32]) et tu lui affecte un pointeur sur une chaine de caractère (char*).
    C'est comme dire qu'un entier et un tableau d'entier sont la même chose.
    Si ton compilo accepte une telle chose, change le . Sinon, poste un code qui compile si tu souhaite avoir une meilleure réponse.

    Autre chose, conventionellement les noms de variables préfixées par un underscore ('_') sont réservés pour les variables d'instances. La convention que tu emploies, c-à-d utiliser ces noms pour les paramètres de fonction est assez embêtante à lire.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    95
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 95
    Points : 42
    Points
    42
    Par défaut
    Oki, je viens de réediter tout ça... effectivement, quelques erreurs se sont glissées dans mon code (qui n'est qu'une représentation de mon code réel qui lui se compile sans erreurs de ce genre). voilà...

    Par ailleurs, chaque case du tableau liste_personne représente une liste de personnes donc de noms chacun gérée par la classe Noms.

    liste_personnes[0] est la 1ère liste de 32 noms...
    liste_personnes[1] est la 2ème liste de 32 noms...
    et ainsi de suite...

    Bon ceci étant résolu, revenons à nos moutons... est-ce possible ou non?

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Eh bien moi, je te conseillerais la première méthode (faire une copie)

    Mais pour l'instant, je ne sais pas trop si les erreurs que je vois dans ton code sont dues à la copie ou sont aussi dans ton code originel. Toujours est-il que tu n'alloues pas de place pour le zéro terminal lors de ta copie.
    Pour éviter des erreurs comme ça, je te conseillerais d'utiliser la fonction _tcsdup()...

    Et bien sur, les précautions d'usage: Initialisation des pointeurs à NULL dans le constructeur, libération de la précédente zone mémoire dans le SetNom(), etc.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Si la question est 'l'allocation d'une chaîne de caractère peut-elle écraser un bloc mémoire utilisé ?' la réponse est non. Si l'allocation dynamique n'est pas possible parce qu'il n'y a plus d'espace disponible, malloc retourne un pointeur nul et n'écrase rien.

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    95
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 95
    Points : 42
    Points
    42
    Par défaut
    ok, alors ça peut être une erreur due à ce caractère de fin '\0'

    Question très bête, comment je libère la précédente mémoire ? avec un free ? Il n'est pas sensé rendre inutilisable le pointeur par la suite ?

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    95
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 95
    Points : 42
    Points
    42
    Par défaut
    ok, alors ça peut être une erreur due à ce caractère de fin '\0'

    Question très bête, comment je libère la précédente mémoire ? avec un free ? Il n'est pas sensé rendre inutilisable le pointeur par la suite ?

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    95
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 95
    Points : 42
    Points
    42
    Par défaut
    ok, alors ça peut être une erreur due à ce caractère de fin '\0'

    Question très bête, comment je libère la précédente mémoire ? avec un free ? Il n'est pas sensé rendre inutilisable le pointeur par la suite ?

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 582
    Points
    41 582
    Par défaut
    je ne dis pas libérer la mémoire passée en paramètre: je parle de libérer ce qui y avait avant à cette case-la quand tu doit y mettre une nouvelle chaîne

    bref, éviter une fuite de mémoire quand je fais:
    SetNom(1, "abc");
    SetNom(1, "def");

    Au fait, tu devrais déclarer SetNom(int i, const char *nom) puisque tu fais une copie: la chaîne passée en paramètre ne sera jamais modifiée par la fonction...

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    95
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 95
    Points : 42
    Points
    42
    Par défaut
    C'est bien ce que j'avais compris en parlant de précédente mémoire et ma question est si je fais ça ça va me poser des problèmes non ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
         void SetNom(int i, const char * nom) 
         {
               free(m_nom[i]);
    //         m_nom[i] = NULL;
               m_nom[i] = _tcsdup(nom);
         }

  13. #13
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 282
    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 282
    Points : 11 036
    Points
    11 036
    Par défaut
    1- oubli de prise en compte du 0 terminal -- ce qui est capital!!
    2- partir en exception si le malloc ne peut allouer
    3- new[] est bien plus simple à utiliser que malloc (pas de sizeof redondant), delete[] qui fonctionne sur les pointeurs nuls, new qui lève des exception en cas d'impossibilité d'allocation
    4- const char* pour les paramètres entrants non modifiales
    5- utiliser une classe RAII-sante. En supposant que std::string n'est pas supporté sur ta plateforme, une classe raii-sante de chaines constantes avec comptage de référence est vite écrite. En plus, cela se valide très bien avec des test unitaires, après plus qu'à utiliser.

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    95
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 95
    Points : 42
    Points
    42
    Par défaut
    ben, c'est à dire que le _tcsdup (strdup pour les TCHAR) a bien arrangé les choses puisqu'il fait lui même ce malloc avec le 0 terminal.

    Ce que j'ai besoin maintenant de savoir c'est comment palier à la fuite mémoire dont parle Médinoc. (le free rend bien inutilisable le pointeur).

    Et accessoirement, quelle la meilleure façon de faire un équivalent à strndup qui duplique n caractères de ma chaine ?

  15. #15
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par norwy
    Ce que j'ai besoin maintenant de savoir c'est comment palier à la fuite mémoire dont parle Médinoc. (le free rend bien inutilisable le pointeur).
    En faisant une classe string, comme te l'as déjà conseillé Luc...


    Citation Envoyé par norwy
    Et accessoirement, quelle la meilleure façon de faire un équivalent à strndup qui duplique n caractères de ma chaine ?
    En mettant un opérateur = dans ta classe string.

  16. #16
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Citation Envoyé par norwy
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
         void SetNom(int i, const char * nom)
         {
               free(m_nom[i]);
    //         m_nom[i] = NULL;
               m_nom[i] = _tcsdup(nom);
         }
    Ben c'est parfait, comme ça! Plus de fuite de mémoire...
    Et si les pointeurs sont bien initialisés à NULL dans le constructeur, ici on tombera sur un free(NULL) qui, selon la norme, n'est pas dangereux.

    Citation Envoyé par JolyLoic
    Citation Envoyé par norwy
    Et accessoirement, quelle la meilleure façon de faire un équivalent à strndup qui duplique n caractères de ma chaine ?
    En mettant un opérateur = dans ta classe string.
    Le rapport???

  17. #17
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Y'a même pas besoin de recréer une classe chaine. Le mieux si le but est de manipuler des TCHAR (enfin un type de caractère quel qu'il soit), c'est d'utiliser une chaîne standard de TCHAR : typedef basic_string<TCHAR> mystring

    D'ailleurs ça ne m'étonnerais pas qu'un TCHAR soit exactement la même chose qu'un wchar_t (à la redéfinition microsoftienne près), et donc que l'on puisse directement utiliser le typedef de la librairie standard pour les chaîne en UNICODE : wstring

    Ca permettra de supprimer tout ce fatras de malloc, free, strcopy et autre archaïsmes hérités du C qui rendent les applis inmaintenables et incompréhensibles.
    Du coup, tout les algos de manips de chaînes seront accessible et notamment la duplication de tout ou une partie de la chaîne.
    Accessoirement, plus aucune gestion de mémoire ne sera nécessaire.

  18. #18
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Un TCHAR, si UNICODE (ou _UNICODE : on voit les deux) est défini (dans les options ou par un #define), c'est un wchar_t
    si UNICODE n'est pas défini, c'est un char.


    Le problème majeur des wchar_t sous Dev-C++, c'est que wcout (et sans doute les autres flux "standard" unicode) ne marche pas. Quand j'ai demandé ici comment le faire marcher, on m'a répondu qu'on n'avait pas encore réussi...

  19. #19
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Puisque l'OP veut de l'unicode, alors wstring est ce qu'il faut.
    Il suffit de récupérer une fonction de transcodage pour l'affichage

Discussions similaires

  1. [JMeter] Mes scénarios ne font rien mais Jmeter dit que tout va bien :(
    Par kahya dans le forum Tests et Performance
    Réponses: 1
    Dernier message: 27/07/2010, 14h32
  2. Réponses: 1
    Dernier message: 27/10/2009, 19h56
  3. [débutant] Mes controles n'ent font qu'à leur tête!
    Par Alouka dans le forum Visual C++
    Réponses: 3
    Dernier message: 25/10/2006, 10h17
  4. Réponses: 7
    Dernier message: 02/12/2005, 13h02
  5. mes pointeurs se "croisent"
    Par salseropom dans le forum C
    Réponses: 16
    Dernier message: 16/11/2005, 09h22

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