Précédent   Forum du club des développeurs et IT Pro > C et C++ > C++ > Langage
Langage Langage C++, Programmation Orientée Objet, Templates, etc. Avant de poster : FAQ C++
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 30/12/2012, 17h50   #1
Nick84
Invité de passage
 
Homme
Inscription : décembre 2011
Messages : 4
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : décembre 2011
Messages : 4
Points : 2
Points : 2
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 :
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 :
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à
Nick84 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/12/2012, 18h50   #2
JolyLoic
Rédacteur/Modérateur
 
Avatar de JolyLoic
 
Homme Loïc Joly
Développeur informatique
Inscription : août 2004
Messages : 4 675
Détails du profil
Informations personnelles :
Nom : Homme Loïc Joly
Âge : 38
Localisation : France

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

Informations forums :
Inscription : août 2004
Messages : 4 675
Points : 9 901
Points : 9 901
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 :
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.
JolyLoic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/12/2012, 20h31   #3
Nick84
Invité de passage
 
Homme
Inscription : décembre 2011
Messages : 4
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : décembre 2011
Messages : 4
Points : 2
Points : 2
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 :
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 :
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!!!
Nick84 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Cette discussion est résolue.
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 22h50.


 
 
 
 
Partenaires

Hébergement Web