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

Langage C++ Discussion :

Problème de segmentation dans l'appel d'une case d'un tableau


Sujet :

Langage C++

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Décembre 2011
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4
    Points : 5
    Points
    5
    Par défaut Problème de segmentation dans l'appel d'une case d'un tableau
    Bonsoir à tous ceux qui vont lire ce message.

    Je suis donc actuellement sur la création d'un petit jeu 2D pour me faire la main, et j'ai utilisé un système de tableau à deux dimensions pour pouvoir stocker les données du monde à charger (en gros, les différentes tiles). Pour cela, j'ai donc une classe WorldManager qui, lors de sa création, génère le tableau dynamiquement via une méthode WorldManager::constructeurTableauDynamique (cette dernière renvoyant un int**). J'utilise donc un pointeur sur pointeur sur int, et j'ai initialisé ce pointeur dans mon header de classe (WorldManager.h) de cette manière : int **worldTab.
    Ensuite, j'ai deux méthodes, une renvoyant un int, qui correspond à la valeur de la case appelée du tableau (prototype: int getWorldTab(int i , int j). Le return est écrit ainsi: return worldTab[i][j];
    L'autre méthode est tout aussi simple, elle permet, à partir de i et de j, de remplir la case du tableau concernée (prototype: void setWorldTab(int i , int j , int set). Voila ce qu'il se passe dans la méthode: worldTab[i][j] = set;
    Mon problème est le suivant: lors de la compilation, aucun message d'erreur, mais lorsque j'initialise le tableau (en lançant le programme) dans mon constructeur pour pouvoir le remplir entièrement de 0, je fais appel à this->setWorldTab(i , j , 0); (this puisqu'il s'agit de la même classe), mon debugger m'indique un problème de segmentation lors du passage à la fonction setWorldTab (lorsque i = 0 et j = 0).
    Je ne comprends donc pas pourquoi mon pointeur worldTab ne pointe pas où il faut, un peu comme si il était perdu ...
    J'implore donc gracieusement votre aide amis développeurs, et j'espère que tout n'est pas trop confus... Voila mes WorldManager.cpp et WorldManager.h (ne faites pas attention aux autres classes créées et etc.., elles n'entrent pas en conflit, du moins à ce qu'il paraît):

    WorldManager.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
    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
     
    #include "WorldManager.h"
    #include "GenerateWorld.h"
    #include "ImageManager.h"
    #include "BlockManager.h"
    #include "Camera.h"
     
    #include <SFML/Graphics.hpp>
    #include <iostream>
     
    WorldManager::WorldManager(int const a_tailleX , int const a_tailleY , sf::RenderWindow *a_app , Camera *a_camera , WorldManager *a_worldManager): generator(0), imageManager(0), blockManager(0), tailleX(a_tailleX), tailleY(a_tailleY), worldTab(0)
    {
        /* Allocation dynamique du tableau */
        worldTab = this->constructeurTableauDynamique();
     
        /* Initialisation */
        for (int i = 0 ; i < tailleX ; i++)
        {
            for (int j = 0 ; j < tailleY ; j++)
            {
                this->setWorldTab(i , j , 0);
            }
        }
     
        //generator = new GenerateWorld(ptrWorldTab, tailleX, tailleY); //Génère le monde dans un WorldGenerator dynamique
        imageManager = new ImageManager(); //Création et chargement des images du monde dans un ImageManager dynamique
        blockManager = new BlockManager(a_worldManager, tailleX, tailleY, imageManager, a_app, a_camera); //Création des blocks pouvant constituer le monde dans un BlockManager dynamique
    }
     
    WorldManager::~WorldManager()
    {
        /* Destruction du double tableau */
        this->destructeurTableauDynamique(worldTab);
     
        delete generator;
        delete imageManager;
        delete blockManager;
    }
     
    int** WorldManager::constructeurTableauDynamique()
    {
        int** m_worldTab = new int* [tailleX];
        for (int i = 0 ; i < tailleX ; i++)
        {
            m_worldTab[i] = new int[tailleY];
        }
     
        return m_worldTab;
    }
     
    void WorldManager::destructeurTableauDynamique(int** m_worldTab)
    {
        for (int i=0; i < tailleX; i++)
        {
            delete[] m_worldTab[i];
        }
        delete[] m_worldTab;
    }
     
    void WorldManager::blitWorld()
    {
        blockManager->blitMap();
    }
     
    int WorldManager::getWorldTab(int i , int j)
    {
        return worldTab[i][j];
    }
     
    void WorldManager::setWorldTab(int i , int j , int set)
    {
        worldTab[i][j] = set;
    }
    WorldManager.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
     
    #ifndef WORLDMANAGER_H_INCLUDED
    #define WORLDMANAGER_H_INCLUDED
     
    #include <SFML/Graphics.hpp>
     
    #include "GenerateWorld.h"
    #include "ImageManager.h"
    #include "BlockManager.h"
    #include "Camera.h"
     
    class WorldManager
    {
        public:
     
        WorldManager(int const a_tailleX , int const a_tailleY , sf::RenderWindow *a_app , Camera *a_camera , WorldManager *a_worldManager);
        ~WorldManager();
     
        int** constructeurTableauDynamique();
        void destructeurTableauDynamique(int** m_worldTab);
     
        void blitWorld();
     
        int getWorldTab(int i , int j);
        void setWorldTab(int i , int j , int set);
     
        private:
     
        GenerateWorld *generator; //Création d'un pointeur sur generator
        ImageManager *imageManager; //Création d'un pointeur sur imageManager
        BlockManager *blockManager; //Création d'un pointeur sur blockManager
     
        //Variables stockant la taille du tableau
        int const tailleX;
        int const tailleY;
     
        int **worldTab;
    };
     
    #endif // WORLDMANAGER_H_INCLUDED
    PS: j'ai bien un destructeur pour mon tableau à deux dimensions, pas de fuite de mémoire de ce côté là

  2. #2
    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 : 49
    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
    Il est fort possible que le problème soit quand même dans tes autres classes, elles peuvent en cas d'erreur écraser la mémoire de ton tableau...

    Ne voyant pas d'erreurs flagrantes (même si la gestion manuelle, c'est moche... Utiliser un vector simplifierait le code), j'ai tenté de recompiler pour voir.

    Après nettoyage j'obtiens :
    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
     
    class WorldManager
    {
        public:
     
        WorldManager(int const a_tailleX , int const a_tailleY);
        ~WorldManager();
     
        int** constructeurTableauDynamique();
        void destructeurTableauDynamique(int** m_worldTab);
     
        void blitWorld();
     
        int getWorldTab(int i , int j);
        void setWorldTab(int i , int j , int set);
     
        private:
     
        //Variables stockant la taille du tableau
        int const tailleX;
        int const tailleY;
     
        int **worldTab;
    };
     
     
    WorldManager::WorldManager(int const a_tailleX , int const a_tailleY ): tailleX(a_tailleX), tailleY(a_tailleY), worldTab(0)
    {
        /* Allocation dynamique du tableau */
        worldTab = this->constructeurTableauDynamique();
     
        /* Initialisation */
        for (int i = 0 ; i < tailleX ; i++)
        {
            for (int j = 0 ; j < tailleY ; j++)
            {
                this->setWorldTab(i , j , 0);
            }
        }
     
    }
     
    WorldManager::~WorldManager()
    {
        /* Destruction du double tableau */
        this->destructeurTableauDynamique(worldTab);
     
    }
     
    int** WorldManager::constructeurTableauDynamique()
    {
        int** m_worldTab = new int* [tailleX];
        for (int i = 0 ; i < tailleX ; i++)
        {
            m_worldTab[i] = new int[tailleY];
        }
     
        return m_worldTab;
    }
     
    void WorldManager::destructeurTableauDynamique(int** m_worldTab)
    {
        for (int i=0; i < tailleX; i++)
        {
            delete[] m_worldTab[i];
        }
        delete[] m_worldTab;
    }
     
    void WorldManager::blitWorld()
    {
    }
     
    int WorldManager::getWorldTab(int i , int j)
    {
        return worldTab[i][j];
    }
     
    void WorldManager::setWorldTab(int i , int j , int set)
    {
        worldTab[i][j] = set;
    }
     
     
    int main()
    {
    	WorldManager mgr(20, 20);
    }
    Ce code compile et s'exécute sans soucis chez moi.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Décembre 2011
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4
    Points : 5
    Points
    5
    Par défaut
    Je viens de tester le code nettoyé, et il fonctionne également chez moi... Le programme s’exécute naturellement sans aucun soucis. Cependant, je ne vois pas pourquoi l'autre plante toujours au même endroit, et je ne vois pas non plus pourquoi il y aurait un conflit avec les autres classes, puisque c'est juste après avoir créé dynamiquement le tableau que je l'initialise, sans rien entre les deux, or c'est bien là qu'il plante... Je vais continuer à repasser mon code au peigne fin, si quelqu'un a une idée sur le pourquoi du comment de ce problème de segmentation, je suis toujours preneur!

    Edit:

    Étrangement, je viens de recompiler et de relancer et l'erreur ne se situe plus au même endroit... Je peux donc bien accéder aux deux méthodes set et get de mon tableau via le this->get/set...
    Cependant, c'est maintenant lorsque j'appel ces 2 méthodes en dehors de WorldManager (donc via un pointeur *worldManager) que mon programme ne fonctionne pas: dans une de mes classes, créée dans worldManager (il s'agit de blockManager, qui possède donc un pointeur sur worldManager), j'appel int x = worldManager->getWorldTab(i , j) où i = 89 et j = 46, et là mon debugger me renvoi encore une erreur de segmentation au niveau du return de getWorldTab...
    J'ai bien entendu vérifié que worldTab[89][46] existé (j'ai fait appel à this->getWorldTab(89 , 46) dans mon constructeur), et à ce niveau là pas de problème de segmentation...
    Je ne comprend vraiment donc pas d'où peut venir l'erreur... Je vais encore chercher, mais si vous pouvez m'aider, voilà mon BlockManager.cpp et .h:

    BlockManager.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
    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
     
    #include "BlockManager.h"
    #include "Terre.h"
    #include "Pierre.h"
    #include "ImageManager.h"
    #include "Camera.h"
    #include "WorldManager.h"
     
    #include <SFML/Graphics.hpp>
    #include <iostream>
     
    BlockManager::BlockManager(WorldManager *a_worldManager, int const a_tailleX, int const a_tailleY, ImageManager *imageManager, sf::RenderWindow *a_app, Camera *a_camera): worldManager(a_worldManager), tailleX(a_tailleX), tailleY(a_tailleY), app(a_app), camera(a_camera), terre(0), pierre(0)
    {
        //Toutes les instances des blocks seront créées ici, et auront pour argument imageManager, pour pouvoir l'utiliser afin de charger les images dans leur constructeur, ainsi que le tableau et ses dimensions
        terre = new Terre(worldManager, a_tailleX, a_tailleY, imageManager);
        pierre = new Pierre(worldManager, a_tailleX, a_tailleY, imageManager);
    }
     
    BlockManager::~BlockManager()
    {
        delete terre;
        delete pierre;
    }
     
    void BlockManager::blitMap()
    {
        int switchCondition;
     
        for (int i = camera->getPosX() / 20 - 1 ; i <= (camera->getPosX() + camera->getWidth()) / 20 + 1 ; i++)
        {
            for (int j = camera->getPosY() / 20 - 1 ; j <= (camera->getPosY() + camera->getHeight()) / 20 + 1 ; j++)
            {
                switchCondition = worldManager->getWorldTab(i , j); //L'erreur vient ici, au premier passage de la boucle (pour info le monde fait 200 * 100, donc avec les différents paramètres le premier passage donne i = 89 et j = 46 comme je l'ai dit plus haut, jusqu'à i = 111 et j = 53)
                switch (switchCondition)
                {
                    case 0:
                        app->Draw(terre->blitTopLeftSprite(i * 20 - camera->getPosX() , j * 20 - camera->getPosY() , i , j));
                        app->Draw(terre->blitTopRightSprite(i * 20 - camera->getPosX() + 10 , j * 20 - camera->getPosY() , i , j));
                        app->Draw(terre->blitBotLeftSprite(i * 20 - camera->getPosX() , j * 20 - camera->getPosY() + 10 , i , j));
                        app->Draw(terre->blitBotRightSprite(i * 20 - camera->getPosX() + 10 , j * 20 - camera->getPosY() + 10 , i , j));
                        //C'est un block d'air, donc rien ne se passe
                        break;
     
                    case 1:
                        app->Draw(terre->blitTopLeftSprite(i * 20 - camera->getPosX() , j * 20 - camera->getPosY() , i , j));
                        app->Draw(terre->blitTopRightSprite(i * 20 - camera->getPosX() + 10 , j * 20 - camera->getPosY() , i , j));
                        app->Draw(terre->blitBotLeftSprite(i * 20 - camera->getPosX() , j * 20 - camera->getPosY() + 10 , i , j));
                        app->Draw(terre->blitBotRightSprite(i * 20 - camera->getPosX() + 10 , j * 20 - camera->getPosY() + 10 , i , j));
                        break;
     
                    case 2:
                        app->Draw(terre->blitTopLeftSprite(i * 20 - camera->getPosX() , j * 20 - camera->getPosY() , i , j));
                        app->Draw(terre->blitTopRightSprite(i * 20 - camera->getPosX() + 10 , j * 20 - camera->getPosY() , i , j));
                        app->Draw(terre->blitBotLeftSprite(i * 20 - camera->getPosX() , j * 20 - camera->getPosY() + 10 , i , j));
                        app->Draw(terre->blitBotRightSprite(i * 20 - camera->getPosX() + 10 , j * 20 - camera->getPosY() + 10 , i , j));
                        break;
     
                }
            }
        }
    }
    BlockManager.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
     
    #ifndef BLOCKMANAGER_H_INCLUDED
    #define BLOCKMANAGER_H_INCLUDED
     
    #include <SFML/Graphics.hpp>
     
    class WorldManager;
     
    #include "Terre.h"
    #include "Pierre.h"
    #include "ImageManager.h"
    #include "Camera.h"
     
    class BlockManager
    {
        public:
     
        BlockManager(WorldManager *a_worldManager, int const a_tailleX, int const a_tailleY, ImageManager *imageManager, sf::RenderWindow *a_app, Camera *a_camera);
        ~BlockManager();
     
        void blitMap();
     
        private:
     
        WorldManager *worldManager;
     
        int const tailleX;
        int const tailleY;
     
        sf::RenderWindow *app;
        Camera *camera;
     
        Terre *terre;
        Pierre *pierre;
     
    };
     
    #endif // BLOCKMANAGER_H_INCLUDED
    Edit :

    J'ai finalement trouvé pourquoi mon code ne fonctionnait pas... C'est tout bête, mais c'est en faisant des essais que je m'en suis rendu compte: en fait, j'ai créé dynamiquement mon worldManager via un pointeur dans une autre classe, et j'ai donné en argument à mon worldManager ce pointeur vers lui-même, puis ce pointeur est directement réutilisé dans le constructeur de worldManager pour le donner en argument à mon fameux blockManager, où il est "enregistré" pour être réutilisé dans toute la classe blockManager. Vous l'aurez constaté, ceci est totalement inutile: pas la peine de donner en argument son propre pointeur à worldManager, puisqu'il le possède déjà (il s'agit de "this"). Ainsi, en supprimant cet argument et en envoyant en argument à blockManager directement this, le programme fonctionne (après quelques autres modifications dans les méthodes de blockManager, bien évidemment), et n'envoi plus aucune erreur de segmentation...

    Je viens donc d'apprendre une chose assez intéressante du c++ sur les pointeurs par moi même, comme quoi, c'est bien en forgeant que l'on devient forgeron

    Cependant, je trouve tout de même cela étrange que l'autre pointeur ne fonctionne pas... Je suppose que l'on ne peut pas donner en argument un pointeur sur classe à cette même classe, car il semble se perdre dans sa propre classe ... Bref, problème résolu!!!

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

Discussions similaires

  1. problème dans l'appel d'une methode
    Par aishaDev dans le forum JSF
    Réponses: 12
    Dernier message: 28/06/2012, 12h00
  2. problème dans l'appel d'une commande Linux dans python
    Par ghadroud dans le forum Général Python
    Réponses: 25
    Dernier message: 20/04/2009, 14h55
  3. pb dans l'appel d'une fonction
    Par badboys206s16 dans le forum ASP
    Réponses: 3
    Dernier message: 04/07/2006, 08h32
  4. Problème de retour aprés l'appel d'une popup
    Par PADAWANN33 dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 06/02/2006, 15h53
  5. [APPLET] beans dans applet appelé depuis une page HTML
    Par Néo-Tony dans le forum Applets
    Réponses: 1
    Dernier message: 04/01/2006, 14h54

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