Partage
  • Partager sur Facebook
  • Partager sur Twitter

C++ - Qt: Segmentation fault dans une fonction

Sujet résolu
    20 janvier 2018 à 19:25:21

    Bonjour à toutes et tous,

    je débute en C++  (Qt avec Qt Creator) avec un certain plaisir à suivre les cours d'OpenClassRoom...

    Je fais des petits essais, et là, je suis tombé sur un os qui m'occupe depuis plusieurs jours.

    La compilation se passe sans erreur. Mais à l'excécution un gentil SEGMENTATION FAULT me sourit.

    En mettant un point d'arrêt au début de la ligne 36, l'erreur survient.

    Fenetre1.cpp

    #include "Fenetre1.h"
    
    Fenetre1::Fenetre1() : QWidget()
    {
        QGridLayout *m_layout1 = new QGridLayout;
        QPushButton *m_bouton_quitter = new QPushButton("Quitter");
        QLabel *m_label_image = new QLabel;
        QPixmap *m_image = new QPixmap;
    
       *m_image=QPixmap("../test-vide/images/IMG_0021.JPG");
       *m_image=m_image->scaled(100,100,Qt::KeepAspectRatio,Qt::FastTransformation);
    
        m_label_image->setPixmap(*m_image);
    
        m_layout1->addWidget(m_bouton_quitter,2,2);
        m_layout1->addWidget(m_label_image,0,0);
        this->setLayout(m_layout1);
        this->setWindowTitle("Fenêtre à modifier");
        //*** essai
        this->setGeometry(50,50,300,200);
        m_label_image->resize(20,20);
        //m_label_image->setFixedHeight(10);
        essai();
    
        QObject::connect(m_bouton_quitter,SIGNAL(clicked()), qApp,SLOT(quit()));
    }
    
    Fenetre1::~Fenetre1()  //destructeur
    {
    // Inutile car Qt le fait pour nous
    }
    
    void Fenetre1::essai()
    {
    
       this->m_label_image->setFixedHeight(10);
    
    }
    
    QLabel* Fenetre1::get_label() const
    {
        return this->m_label_image ;
    }
    QPixmap* Fenetre1::get_image() const
    {
       return this->m_image;
    }
    



    Fenetre.h

    #ifndef FENETRE1_H
    #define FENETRE1_H
    
    #include <QApplication>
    #include <QWidget>
    #include <QGridLayout>
    #include <QPushButton>
    
    #include <QLabel>
    #include <QPixmap>
    
    
    class Fenetre1 : public QWidget
    {
        public:
            Fenetre1();
            //Essai
    
            void essai();
            QLabel *get_label();
            QPixmap *get_image();
    
    
    
    
        private :
            QLabel *m_label_image;
            QPixmap *m_image;
            QGridLayout *m_layout1;
            QPushButton *m_bouton_quitter;
    
    };
    
    #endif // FENETRE1_H
    

    main.cpp

    #include <QApplication>
    #include "Fenetre1.h"
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
    
        Fenetre1 *fenetre1;
        fenetre1= new Fenetre1;
    
        fenetre1->move(400,0);
        fenetre1->show();
        return app.exec();
    }
    



    Je précise que j'ai lu des dizaines de post sur le sujet, mais, je n'ai pas trouvé mon bonheur...

    D'avance merci pour votre aide à venir.

    Franck.

    -
    Edité par FranckRAZAFIMAHARO 21 janvier 2018 à 9:04:13

    • Partager sur Facebook
    • Partager sur Twitter
    Astromout
      20 janvier 2018 à 22:07:01

      Salut,

      Que crois tu faire avec le code suivant (qui se trouve dans ton constructeur)?

      QLabel *m_label_image = new QLabel;

      Notes d'ailleurs que je pourrais te poser la même question pour

      QGridLayout *m_layout1 = new QGridLayout;

      et pour

      QPushButton *m_bouton_quitter = new QPushButton("Quitter");

      Ne te méprends pas, je sais ce que tu veux faire, mais, pas de bol, ce n'est pas ce que tu fais ;)

      • Partager sur Facebook
      • Partager sur Twitter
      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
        20 janvier 2018 à 22:14:13

        Bonsoir Koala01,

        quelle joie de voir que l'on est lu :)

        A priori, je crois déclarer et instancier dynamiquement des objets (plus précisément des pointeurs qui pointent vers un espace mémoire 'custumisé' avec respectivement les types QLabel, QPushbutton...).

        Je ne me suis pas posé d'autres questions dans la mesure où lorsque j'enlève la ligne 36 du .cpp, ça compile et ça s'exécute sans erreur...

        Et, là, je donne ma langue au chat. :o : au vu de tes questions que j'adore, je pense qu'il manque quelque chose qui va dire à l'ordinateur que tel objet va prendre tel ou tel espace dans la mémoire...

        J'attends la suite avec impatience.

        -
        Edité par FranckRAZAFIMAHARO 20 janvier 2018 à 22:27:29

        • Partager sur Facebook
        • Partager sur Twitter
        Astromout
          20 janvier 2018 à 22:20:31

          FranckRAZAFIMAHARO a écrit:


          A priori, je crois déclarer et instancier dynamiquement des objets...

          Sauf que ce n'est visiblement pas ce que tu fais :D

          Alors, essayons de réfléchir un peu: où ta variable m_label_image est-elle sensée être déclarée? et où est-elle sensée être définie?

          Je ne me suis pas posé d'autres questions dans la mesure où lorsque j'enlève la ligne 36 du .cpp, ça compile et ça s'exécute sans erreur...

          Et c'est normal, car la ligne 36 n'est que l'endroit du code où un problème qui trouve son origine (beaucoup) plus tôt devient apparent parce que tu essaye de déréférencer une adresse invalide ;)

          • Partager sur Facebook
          • Partager sur Twitter
          Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
            21 janvier 2018 à 5:42:17

            Bonjour,

            merci Kaoala one...

            • apparemment, il faut que je comprenne déclaration  et définition...je préfère m'abstenir (je lis, relis, re-relis différentes sources)
            • afin d'utiliser m_label_image dans les méthodes/fonctions de Fenetre1, il faut que je déclare m_label_image en dehors du constructeur de la classe Fenetre1.
            • Ai-je bien compris? Il faut que je déclare m_label_image avec une portée qui englobe  le constructeur et les fonctions de la classe Fenetre1. Faut-il donc que la déclaration de m_label_image se fasse aussi en dehors du prototype de Fenetre1
            • il y a peut-être un mot clé à ajouter, mais, là, je ne vais pas me lancer à l'aveugle...et vu le sens de ta réponse, je ne pense pas que ce soit la bonne voie (ou du moins, il faut que je mette les déclarations ailleurs pour qu'elles soient visibles dans toute la classe Fenêtre).
            • après, pour les définitions...j'aurai bien été tenté de le faire dans le constructeur (.cpp), les déclarations dans le .h.

            En tout cas, c'est bien agréable d'être guidé de la sorte.:) même si je patauge dans le potage.

            Allez, je me lance avec le risque de me faire gronder :

            Faut-il que m_label_image soit un attribut "statique" de la classe Fenetre1? J'ai mis les guillemets car j'entends par statique : "accessible par les fonctions de la classe" , mais je veux que chaque instance de la classe aura son propre m_label_image?

            :-°..

            Puis : j'essaie de voir le "où on fait ceci"...mais, ensuite, j'aimerai aussi trouve le "comment", i.e., "comment on l'écrit".

            Ainsi, est-ce que l'on définit l'attribut m_label_image avec un signe "=" et la déclare-t-on avec "QLabel m_label_image;"? Je pose cette question car j'ai l'impression que parfois définition et déclaration sont faites sur la même ligne et suis incapable de dire ce qui est fait exactement.

            Mille merci pour la décomposition du problème.

            -
            Edité par FranckRAZAFIMAHARO 21 janvier 2018 à 9:28:02

            • Partager sur Facebook
            • Partager sur Twitter
            Astromout
              21 janvier 2018 à 12:54:31

              On va poser la question comme cela: qu'est-ce qui fait que le compilateur sait que l'on déclare une variable? et, d'un autre coté, qu'est ce qui  fait que le compilateur sait qu'on utilise une variable (par exemple, pour la définir ou... pour faire appel à une de ses fonctions membres?

              Pour t'aider à comprendre, quelle différence y aura-t-il entre le code

              int main(){
                   int i = 3;
                   std::cout<<"i = "<<i<<"\n";
                   {
                       int i = 5;
                       std::cout<<"i = "<<i<<"\n";
                   }
                   std::cout<<"i = "<<i<<"\n";
              }

              et le code

              int main(){
                   int i = 3;
                   std::cout<<"i = "<<i<<"\n";
                   {
                       i = 5;
                       std::cout<<"i = "<<i<<"\n";
                   }
                   std::cout<<"i = "<<i<<"\n";
              }

              Pourquoi les deux codes provoqueront-ils un résultat différent?


              -
              Edité par koala01 21 janvier 2018 à 12:56:34

              • Partager sur Facebook
              • Partager sur Twitter
              Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                21 janvier 2018 à 14:59:06

                En espérant avoir compris, mais surtout en m'exprimant de manière la plus rigoureuse possible :

                En écrivant ceci, que 

                int i=5;

                cela revient à :


                int i; // Déclaration d'une variable i de type int
                
                i=5; //Définition de i

                Dans le premier programme proposé, int i=5; apparaît deux fois. La première en dehors du bloc, et la deuxième à l'intérieur de ce dernier.

                Ainsi, on créée deux variables de type int qui sont homonymes, mais, ces deux variables sont totalement indépendantes. La portée de celle dans le bloc {} est justement limitée entre les deux {}.

                Lorsque l'on exécute ce premier programme, on obtient :

                i=3  (premier retour du flux cout)

                i=5 (deuxième retour du flux : il s'agit de la valeur du deuxième homonyme)

                et enfin i=3 : le deuxième homonyme a été zigouillé par l' "ordinateur" car on est en dehors du bloc.

                Dans le deuxième programme proposé, il n'y a pas d'autre déclaration avec type nom_de_variable; .

                Ainsi, lorsque l'on écrit dans le bloc

                   {
                         i = 5;
                         std::cout<<"i = "<<i<<"\n";
                     }


                Il n'y a qu'une seule variable dont le nom est i, et surtout, la ligne 2 ci-dessus attribut la valeur 5 à la variable que l'on a définit en dehors du bloc.

                On obtient donc

                i=3

                i=5

                i=5

                Enfin, la variable i est bien reconnue dans le bloc, car le bloc est dans le bloc où i a été déclarée.

                {//début du bloc principal
                   //Déclaration + définition de i
                   
                     {\* début du bloc intermédiaire
                          changement de la valeur de i
                          toute variable définie ici sera morte à la 
                          fin de ce bloc intermédiaire */
                
                 } // fin du bloc intermédiaire
                }   // fin du bloc principal
                
                
                



                La difficulté est que j'ai le main.cpp, le .h et le .cpp de la classe...Sans oublier l'instance de la classe que j'ai crée dans le main.

                 Merci Koala one! Mon cerveau tourne à plein pôt! J'essaie d'avancer sur mon problème, en attendant impatiemment la suite!o_O et en espérant me coucher moins bête ce soir.

                koala01 a écrit:

                On va poser la question comme cela: qu'est-ce qui fait que le compilateur sait que l'on déclare une variable? et, d'un autre coté, qu'est ce qui  fait que le compilateur sait qu'on utilise une variable (par exemple, pour la définir ou... pour faire appel à une de ses fonctions membres)?

                Réponse de Franck

                Pour "Qu'est-ce qui fait que le compilateur sait que l'on déclare une variable" : je pense qu'il faut déclarer la variable au bon endroit. m_Label_image dans mon cas doit être déclarée pour tous les membres de la classe Fenetre1 et en particulier pour les méthodes membre de la classe.

                Pour la deuxième partie de la question "qu'est-ce qui fait que le compilateur sait que l'on utilise une variable" : je ne sais pas :'(, à moins que : pour le faire il suffit d'écrire son nom.

                -
                Edité par FranckRAZAFIMAHARO 21 janvier 2018 à 16:36:03

                • Partager sur Facebook
                • Partager sur Twitter
                Astromout
                  21 janvier 2018 à 16:35:05

                  Bon, je vois que tu as compris...

                  Maintenant, observe un tout petit peu ta classe et ton constructeur, que je vais mettre dans le même bloc de code:

                  class Fenetre1 : public QWidget
                  {
                      public:
                          Fenetre1();
                          //Essai
                   
                          void essai();
                          QLabel *get_label();
                          QPixmap *get_image();
                   
                   
                   
                   
                      private :
                          QLabel *m_label_image;
                          QPixmap *m_image;
                          QGridLayout *m_layout1;
                          QPushButton *m_bouton_quitter;
                   
                  };
                  Fenetre1::Fenetre1() : QWidget()
                  {
                      QGridLayout *m_layout1 = new QGridLayout;
                      QPushButton *m_bouton_quitter = new QPushButton("Quitter");
                      QLabel *m_label_image = new QLabel;
                      QPixmap *m_image = new QPixmap;
                      /* ... */
                  }

                  A ton avis, que se passe-t-il?

                  PS: ou bien on m'appelle koala, ou bien on m'appelle koala01, mais pas koala one :D

                  -
                  Edité par koala01 21 janvier 2018 à 16:36:29

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                    21 janvier 2018 à 18:56:36

                    Ah,

                    je sens que ça chauffe, mais bon, je n'ai aucun recul.:o

                    C'est comme si j'avais pour chaque variable : deux attributs homonymes avec seulement le deuxième qui est défini.

                    Là, je surchauffe du cerveau.

                    Il faut sûrement que je me débrouille pour n'avoir qu'une seule déclaration comme pour l'exemple que tu m'as soumis avec l' "int i;" du post précédent...mais, je suis à deux doigts de la syncope : il est très difficile de voir l'évidence, et encore plus de corriger ses propres fautes!

                    J'vois rien:soleil:, merci koala...

                    J’essaye d'enlever tous les types au début du constructeur pour ne pas me retrouver avec des homonymes, mais, ensuite je me retrouve avec des problèmes d'homogénéité dans les types..est-ce quand même la bonne voie?

                    Voilà :honte:...ça fonctionne!

                    Fenetre.h

                    #ifndef FENETRE1_H
                    #define FENETRE1_H
                    
                    #include <QApplication>
                    #include <QWidget>
                    #include <QGridLayout>
                    #include <QPushButton>
                    
                    #include <QLabel>
                    #include <QPixmap>
                    
                    class Fenetre1;
                    
                    
                    class Fenetre1 : public QWidget  //Définition de la classe
                    {
                    
                        public:
                            Fenetre1(); //Déclaration du constructeur
                            ~Fenetre1(); //Déclaration du destructeur
                    
                            void essai();
                            QLabel *get_label() const;
                            QPixmap *get_image() const;
                    
                        private :
                            QPixmap *m_image; //Déclaration d'un pointeur qui ne pointe sur rien pour le moment
                            QGridLayout *m_layout1;
                            QPushButton *m_bouton_quitter;
                            QLabel*m_label_image;
                    
                    };
                    
                    #endif // FENETRE1_H
                    

                    Fenetre.cpp

                    #include "Fenetre1.h"
                    
                    
                    Fenetre1::Fenetre1() : QWidget()
                    {
                        m_layout1 = new QGridLayout;
                        m_bouton_quitter = new QPushButton("Quitter");
                        m_label_image = new QLabel(); // Ici, le pointeur créé dans .h. grâce à new, on affecte une adresse au pointeur.
                        m_image = new QPixmap;
                    
                       *m_image=QPixmap("../test-vide/images/IMG_0021.JPG");
                       *m_image=m_image->scaled(100,100,Qt::KeepAspectRatio,Qt::FastTransformation);
                    
                        m_label_image->setPixmap(*m_image);
                    
                        m_layout1->addWidget(m_bouton_quitter,2,2);
                        m_layout1->addWidget(m_label_image,0,0);
                        this->setLayout(m_layout1);
                        this->setWindowTitle("Fenêtre à modifier");
                        //*** essai
                        this->setGeometry(50,50,300,200);
                        m_label_image->resize(20,20);
                        //******
                        essai();
                    
                        QObject::connect(m_bouton_quitter,SIGNAL(clicked()), qApp,SLOT(quit()));
                    }
                    
                    Fenetre1::~Fenetre1()  //destructeur
                    {
                    // Inutile car Qt le fait pour nous
                    }
                    
                    void Fenetre1::essai()
                    {
                        this->m_label_image->setFixedHeight(50);
                    }
                    
                    QLabel* Fenetre1::get_label() const
                    {
                        return this->m_label_image ;
                    }
                    QPixmap* Fenetre1::get_image() const
                    {
                       return this->m_image;
                    }
                    

                    Et, là, pas de fuite de mémoire.:)...Je vais pouvoir dormir, me laver, manger avec sérénité et joie!

                    Le sujet est donc résolu.

                    Koala, you are the one! Je n'aurai jamais compris cette finesse seul.

                    Franck.



                    -
                    Edité par FranckRAZAFIMAHARO 21 janvier 2018 à 21:29:19

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Astromout

                    C++ - Qt: Segmentation fault dans une fonction

                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                    • Editeur
                    • Markdown