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 :

Probleme de Pointeur


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2007
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Février 2007
    Messages : 22
    Par défaut Probleme de Pointeur
    Bonjour à tous,

    Je vous explique un peu ce que je fais avant d'expliquer ce qui ne vas pas.

    Je dois creer deux classes, l'une pouvant stocker des "char" dans un tableau et pouvant pointer sur un objet du meme type de cette classe, appelons la Element, et une autre classe (on l'appelera lista) regroupant des Elements (l'objet). C'est donc une liste d' Elements. Le but final est de pouvoir lire un fichier avec des caracteres, de stocker chaque ligne dans un object Element (donc de mettre tous les symboles dans le tableau) et faire pointer le 1er objet vers le second, et le second vers le 3eme, etc.

    Un objet de Lista representera donc, de maniere dérivée, toutes les lignes du fichiers.

    Bon j'espere que vous avez compris, je vous montre le programme maintenant:


    lista.h
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    #include <cstdlib>
    #include <iostream>
    #include <new>
     
     
    using namespace std;
    extern int size_table ;
     
    class Element {         
          char *Table;
          int Dimension;
          Element *next ;
     
    public :
     
    #include <cstdlib>
    #include <iostream>
    #include <new>
     
     
    using namespace std;
    extern int size_table ;
     
    class Element {         
          char *Table;
          int Dimension;
          Element *next ;
     
    public :
     
           //  Constructeur
           Element(int=3);
     
           //  Destructeur
           ~Element();
     
           //  Constructeur de copie
           Element(const Element&);
     
           // permet d'initialiser le tableau d'un objet element (c'etait une fonction juste pour tester)
           void setElement(int,int);
     
           // permet d'acceder au pointeur next d'element depuis l'exterieur
           Element * return_next() { return next;}
     
           // Servira pour la lecture du fichier et l'ecriture egalement
           Element & operator=(char *) const;
           char* & operator=(const Element&) const;        
     
     
           // Affiche le contenu d'un objet Element
           friend  ostream &operator<<(ostream& o, Element&);
    };
     
    class Lista : public Element {         
          Element *Work;
     
    public :
           // Constructeur
           Lista();
     
            //  Destructeur
           ~Lista();
     
           // Constructeur par copie
           Lista(const Lista&);  
     
    };
    lista.ccp
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
     
    #include "Lista.h"
     
    // Constructeur 
    Element::Element(int a) {
        Table = new char[Dimension=a];
       	for (int i=0;i<Dimension;i++) {
    		Table[i]=0;
    	}
    	next = NULL ;
    }
     
    // Constructeur par copie 
    Element::Element(const Element & Elementcopy) {
           Dimension =Elementcopy.Dimension;
           Table= new (nothrow) char[Dimension];
     
           for(int i=0; i<Dimension; i++) {
                 Table[i]= Elementcopy.Table[i] ;
           }
           next = Elementcopy.next ;
    } 
     
    // Servira a la lecture du fichier
    Element & Element::operator=(char *Table_char) const {
            Element M(size_table);
            for(int i=0; i<M.Dimension; i++) {
                    M.Table[i]=Table_char[i] ;
            }
            return M;        
    }
     
    // Servira a l'ecriture du fichier
    char * & Element::operator=(const Element &M) const {
           char * return_Table = new char[M.Dimension];
           for(int i=0; i<M.Dimension; i++) {
                    return_Table[i]=M.Table[i] ;
           }
           return return_Table;
    }
     
    // Destructeur
      Element::~Element() {
           delete[] Table; 
    }
     
    // Accede au contenu d'un object Element
     void  Element::setElement(int indice,int valeur) {
    	Table[indice]=valeur;
     }
     
    // Affiche un objet Element
      ostream & operator<<(ostream& o, Element &M) {
              int i;
     
              for(i=0; i<M.Dimension; i++){
                       o<<"\t";
                       o<<M.Table[i]<<"\t";
                       o<<endl;
              }
     
              o<<endl;   
              return o;
    }
     
    // Constructeur de lista     
    Lista::Lista() {
        Work = NULL ;
    }
     
    // Constructeur par copie 
    Lista::Lista(const Lista & Listacopy) {
        if (Listacopy.Work == NULL) cout << "Nothing to copy" << endl ;
        else {             
             Element *suivant;
             Work = Listacopy.Work;         
             suivant = (Listacopy.Work)->return_next();        
             while (suivant!= NULL) {
                   Work = Work->return_next();
                   Work = suivant;
                   suivant = suivant->return_next();            
             }
     
        }
    }    
     
    // Destructeur par copie 
    Lista::~Lista() {
           Element *n;
           Element *Suiv;       
           n = Work;
           while (n!= NULL) {
                 Suiv = n->return_next();
                 delete[] n; 
                 n=Suiv;           
           }
     
           delete[] n; 
    }
    main.cpp

    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
     
    #include "Lista.h"
     
    int size_table=0 ;
     
    int main(int argc, char *argv[]) {
    	Element M(4);   // Creation d'un Element
    	Element Aut(2); // Creation autre Element
    	Aut.setElement(0,6); // Initialisation
    	Aut.setElement(1,6);
        M.return_next() =  &Aut ;  // Je veux faire pointer M.return_next() vers l'Element Aut
    	if (M.return_next()==NULL) cout << "Marche Pas" <<endl ;
     
        system("PAUSE");
        return EXIT_SUCCESS;
    }

    Ok donc dans mon main, je voulais tester si ce que j'avais fais avant marchait donc j'ai creé deux objets Element, de dimension differente et je voulais faire pointer le voisin de M (qui est next) vers A.
    Si je ne m'abuse, M->next étant un pointeur, je peux faire "pointer" ce pointeur vers l'Element Aut en utilisant la syntaxe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    M.return_next() =  &Aut ;

    Cependant j'obtiens une erreur de compilation du genre "non lvalue in assignement". Je comprend ce que ce message signifie mais je comprend absolument pourquoi je l'obtiens.

    En esperant avoir été clair, je vous remercie de vos réponses!

    PS: je rappelle que j'étais en train de tester le programme donc si vous voyez des erreurs que j'aurais faites dans les autres parties, c'est normal que je ne les ai pas encore vues (mais bon si vous en voyez, merci de me les signaler)

    Nico

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Bonjour,
    • S'il ne s'agit pas d'un exercice de cours, alors il vaut mieux utiliser std::string et un conteneur (std::list ou std::vector).
    • Un opérateur '=' en const, voilà quelque chose d'original!
    • operator=: Comme te le dis le compilateur, retourner la référence d'un objet locale:
    • setElement: aucune vérification si indice est bien dans la plage autorisée
    • return_next ne te permet en aucun cas de modifier la valeur de l'attribut next de l'instance à laquelle elle s'applique. La procédure habituelle est de faire un set_next! Ce que tu retourne, c'est la valeur de next et non une référence ou une adresse sur next permettant d'en modifier la valeur.
    • Le constructeur par copie de Lista ne fonctionne pas.
    • Dans le destructeur de Lista, delete[] c'est pour désalloué un tableau alloué par new XX[].
    • La classe lista fait détruit les objets Element, alors qu'elle ne les a pas alloué et que la gestion de la copie n'est pas faite:

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Février 2007
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Février 2007
    Messages : 22
    Par défaut
    Je te remercie de tes remarques tres constructives.

    - C'est bien en exercice pour débutant, afin d'apprendre à programmer en C++

    - Il est vrai que pour setElement je n'ai mis aucune sécurité mais cette fonction n'a été implentée que pour mes propres tests et sera effacée ulterieurement donc pas de panique:

    - Concernant return_next, je ne comprend pas pourquoi je retournerais une valeur et non une adresse puisque je retourne une variable de type *Element, qui est un pointeur non?

    Supposons que j'ai compris ce que je viens de mettre au dessus, et qu'en effet, je retourne bien une adresse, pour pouvoir faire pointer next sur qqch, je peux utiliser la fonction set_next qui ressemblerais à

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void set_next(Element * a_pointer) { next = a_pointer;}
    que j'utiliserai de cette facon - Ensuite je ne comprend pas ta remarque sur "un operateur en const" . Aurais-je encore fait quelque chosie d'incensée? (ce qui m'etonnerais pas vu mon niveau de débutant).

    - Ok compris concernant la fonction delete[]. Il me suffit de remplacer seulement les delete [] par des delete, qui (suivant ma logique) ferait un appel au destructeur de la classe Element.

    - Ensuite, je ne vois pas pourquoi le constructeur de copie de Lista ne marche pas. Je l'ai pourtant fait au prealable sur une feuille pour voir les etapes de programmation et il me semble que ce soit la bonne méthode. Alors il est vrai que je dois maintenant (si j'ai bien compris la chose), utiliser set_next à la place de return_next pour pouvoir bien modifier mon pointeur, mais je pense que l'algorythme en lui même est bon.

    - Je n'ai pas compris cette remarque : La classe lista fait détruit les objets Element, alors qu'elle ne les a pas alloué et que la gestion de la copie n'est pas faite

    Tes remarques sont trés courtes mais ca m'a fait pas mal avancer et reflechir et j'éspere avoir su corriger ces erreurs.

    Nico.

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    On reprend dans l'ordre:
    Citation Envoyé par Mikolay Voir le message
    - Il est vrai que pour setElement je n'ai mis aucune sécurité mais cette fonction n'a été implentée que pour mes propres tests et sera effacée ulterieurement donc pas de panique:
    C'est un bon réflexe que d'implémenter dès le début quelque chose de correct. L'expérience montre que ce qu'on a fait vite fait en disant 'je reviendrais dessus' ou 'je le virerais ensuite' devient quelque chose qu'on finit par utiliser sans être revenu dessus
    Citation Envoyé par Mikolay Voir le message
    - Concernant return_next, je ne comprend pas pourquoi je retournerais une valeur et non une adresse puisque je retourne une variable de type *Element, qui est un pointeur non?
    Element *next: quand tu retourne next, tu retourne l'adresse de l'élément. Donc tu peux modifier cet élément. Ce que tu veux modifier toi, c'est pas l'élément, mais l'adresse qui te donne l'élément. Donc tu aurais du utiliser &next, l'adresse de l'adresse. Parenthèse mise à part, utilise plutôt le set_next!

    Citation Envoyé par Mikolay Voir le message
    Supposons que j'ai compris ce que je viens de mettre au dessus, et qu'en effet, je retourne bien une adresse, pour pouvoir faire pointer next sur qqch, je peux utiliser la fonction set_next qui ressemblerais à

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void set_next(Element * a_pointer) { next = a_pointer;}
    que j'utiliserai de cette facon
    Oui.
    Citation Envoyé par Mikolay Voir le message
    - Ensuite je ne comprend pas ta remarque sur "un operateur en const" . Aurais-je encore fait quelque chosie d'incensée? (ce qui m'etonnerais pas vu mon niveau de débutant).
    L'opérateur '=' est l'opérateur d'affectation. Il ne peut donc pas être const pour l'objet sur lequel il s'applique puisqu'il s'agit de lui donner une nouvelle valeur. Donc effectivement, c'est insensé.

    Citation Envoyé par Mikolay Voir le message
    - Ok compris concernant la fonction delete[]. Il me suffit de remplacer seulement les delete [] par des delete, qui (suivant ma logique) ferait un appel au destructeur de la classe Element.
    new -> delete pour 1 objet. new [] -> delete [] pour un tableau d'objet.
    Citation Envoyé par Mikolay Voir le message
    - Ensuite, je ne vois pas pourquoi le constructeur de copie de Lista ne marche pas. Je l'ai pourtant fait au prealable sur une feuille pour voir les etapes de programmation et il me semble que ce soit la bonne méthode. Alors il est vrai que je dois maintenant (si j'ai bien compris la chose), utiliser set_next à la place de return_next pour pouvoir bien modifier mon pointeur, mais je pense que l'algorythme en lui même est bon.
    Je pense que tu as confondu la copie de la valeur de l'élément courant et la copie de son adresse. Telle que tu l'as écrit, l'instance par copie a un objet Work qui pointe sur le dernier élément de la liste de Listacopy.
    Citation Envoyé par Mikolay Voir le message
    - Je n'ai pas compris cette remarque : La classe lista fait détruit les objets Element, alors qu'elle ne les a pas alloué et que la gestion de la copie n'est pas faite
    Dans le destructeur tu fais des delete sur Work, mais nulle part il y a des allocs. Je présumme que ta classe est incomplète. Il faut garder en mémoire que la libération doit être faite au même niveau que l'allocation.

    Citation Envoyé par Mikolay Voir le message
    Tes remarques sont trés courtes mais ca m'a fait pas mal avancer et reflechir et j'éspere avoir su corriger ces erreurs.

    Nico.
    J'espère que tu as pu progresser.

    Quelques conseils:
    1/Quand on fait une liste, on sépare le contenu du chaînage: tu devrais avoir quelque chose comme ça:
    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
     
    class CElement
    {
    private:
          char *Table;
          int Dimension;
    ....
    };
    class CChainonElement
    {
    private:
         CElement m_Element;
         CChainonElement *m_pSuivant;
    ...
    };
     
    class CListeElement
    {
    private:
         CChainonElement *m_pPremier;
    };
    L'héritage n'a pas vraiment de sens.
    A mon avis, progresse par étape. Fais une classe CElement dans laquelle tu apprend à gérer le pointeur, son allocation, sa libération, sa copie, la gestion du constructeur par copie et de l'opérateur '='. Maîtriser ça, c'est résoudre beaucoup des problèmes que tu pourrais faire!
    Ensuite, tu reproduis sur CChainonElement ;
    Et enfin CListeElement.
    J'ai l'impression que tu es parti sur tout en même temps et tu t'embrouilles un peu.

    N'hésites pas à faire un tour du côté des tutos. Tu peux aussi poster du code qui marche pour avoir des conseils au fur à mesure de ton avancement.
    Bon courage.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Février 2007
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Février 2007
    Messages : 22
    Par défaut
    J'ai compris pas mal de truc et je vais essayer de bien les programmer. C'est vrai que j'ai fais un peu tout et que je me suis légérement embrouillé. Je vais reprendre étape par étape.

    Même si tu as raison concernant la séparation du contenu du chaînage avec le reste, cela reste un exercice assez scolaire et les étapes de programmation m'imposait de creer deux classes : Element et Lista.

    Je vais avancer et je te riens au courant.

    Merci beaucoup de ton aide et de ta patience, qui sont ici trés efficaces.

    Nico
    --------------------------------------------------------------------
    Deuxieme MAJ

    Bon alors j'ai essayé de modifier ce que j'avais compris et voila ce que ca donne :

    - Constructeur par copie de Lista
    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
     
    Lista::Lista(const Lista & Listacopy) {
        if (Listacopy.Work == NULL) cout << "Nothing to copy" << endl ;
        else {             
             Element *suivant, *n;
             Work = Listacopy.Work;
             n = Work;
             suivant = (Listacopy.Work)->return_next();        
             while (suivant!= NULL) {;
                   n= n->return_next() ;     
                   n = suivant;
                   suivant = suivant->return_next() ;          
             }
     
        }
    }
    Je crois que maintenant cela marche car je ne modifie plus Work mais bien un objet Element parcourant ListaCopy

    -
    Dans le destructeur tu fais des delete sur Work, mais nulle part il y a des allocs. Je présumme que ta classe est incomplète. Il faut garder en mémoire que la libération doit être faite au même niveau que l'allocation.
    Je suis completement d'accord ,je libere seulement ce que je crée.
    Lista est supposé etre une liste d'objet Element
    donc pour detruire cette liste, je detruits chacun des
    objets Element.

    Encore un truc que j'ai du mal à comprendre alors si ca me semble bon...

    - Sinon pour mes opérateurs =:, j'ai bien sur enlevé le type const


    J'ai revu procédrure par procédure et je pense que dans l'ensemble (sauf bug ci dessous), je ne les ai pas baclées et que le programme devrait maintenant marcher.
    J'ai fait un test avec set_next, et cela marche impécable.

    Merci encore une fois, tu m'es d'une grande aide et ce sans en rajouter.

    Nico

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    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
     
    Lista::Lista(const Lista & Listacopy) {
        if (Listacopy.Work == NULL) cout << "Nothing to copy" << endl ;
        else {             
             Element *suivant, *n;
             Work = Listacopy.Work;
             n = Work;
             suivant = (Listacopy.Work)->return_next();        
             while (suivant!= NULL) {;
                   n= n->return_next() ;     
                   n = suivant;
                   suivant = suivant->return_next() ;          
             }
     
        }
    }
    Ce code ne fait rien ou presque. Disons, que la boucle est inutile telle que tu l'as écrite. Normalement, un constructeur de copie devrait ressembler à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Lista::Lista(const Lista & Listacopy)
    Si Listacopy est vide
        alors this est vide
    Sinon
        Parcourir tous les éléments de la liste Listacopy:
              Copier l'élément courant de Listacopy.
              Rajouter cette copie à this.
        Fin parcours.
    Ce n'est pas ce que ton code fait!
    P.S.: il y a une autre façon qui est de récupérer la même liste et de gérer au niveau des pointeurs un compteur de référence, mais je pense que pour l'instant c'est prématuré par rapport à ce que tu veux faire.

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

Discussions similaires

  1. probleme de pointeur ....
    Par berg dans le forum C
    Réponses: 6
    Dernier message: 12/01/2006, 22h46
  2. Probleme de pointeur
    Par Naruto_kun dans le forum C
    Réponses: 17
    Dernier message: 14/12/2005, 20h47
  3. Probleme de pointeurs
    Par mickyoun dans le forum C++
    Réponses: 9
    Dernier message: 10/08/2004, 17h15
  4. Probleme de pointeur sur une fonction
    Par nicky78 dans le forum C
    Réponses: 2
    Dernier message: 23/05/2004, 20h26
  5. probleme avec pointeurs de structures
    Par remi77 dans le forum C
    Réponses: 2
    Dernier message: 20/10/2003, 13h19

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