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 :

[C++] Comment charger tableau à 3 dimensions avec des caractères à partir d'un .txt ?


Sujet :

C++

  1. #1
    Membre du Club
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    Points : 44
    Points
    44
    Par défaut [C++] Comment charger tableau à 3 dimensions avec des caractères à partir d'un .txt ?
    Bonjour à tous,

    Je suis étudiant en DUT Info 1ère année et on a à réaliser un projet mais je suis bloqué dès le commencement.

    En effet, on a un fichier texte qui comprend un labyrinthe de ce type :
    11 9 7
    ###########
    ###########
    ###########
    ###########
    ###########
    ###########
    ###########
    ###########
    ###########

    #D#########
    #+++#+#+++#
    #+###+#####
    #+#+#+++++#
    #+#+###+#+#
    #+++#+++#+#
    ###########
    #+++#+#+++#
    ###########
    etc.

    On doit allouer un tableau dynamique à 3 dimensions. En effet, les nombres du début représentent :
    - 11 le "x"
    - 9 le "y"
    - 7 le "z" (le nombre de plateaux).

    Comment donc initialiser mon tableau à partir de la lecture automatique de ces 3 nombres et stocker tous les caractères (#,+,D,etc) dans ce même tableau ?
    Sachant qu'après, l'affichage du labyrinthe se fait à partir de la relecture de ce tableau dynamique ?

    Je remercie par avance tous ceux qui m'aideront.

  2. #2
    Membre régulier
    Inscrit en
    Septembre 2007
    Messages
    267
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Septembre 2007
    Messages : 267
    Points : 119
    Points
    119
    Par défaut
    Je pense que le mieux c'est de passer par une classe.
    Par exemple :

    Une classe Tab qui aurait pour arguments prives
    unsigned char ***Values
    int x
    int y
    int z
    En public, tous les constructeur, destructeur et le blabla, et en +:
    un constructeur Tab(char * filename), dans lequel tu fera :
    aFile = open(filename)
    aFile >>xx
    setX(xx)
    pareil y et z puis
    triplebouclesurXYZ
    aFile>>var
    Values[i][j][k]=(unsigned char)var


    afile.close


    Dans ton constructeur de base, ou dans une fonction alloue() qui sera appele par tout tes constructeur, tu va devoir alouer comme ca:
    Values = unsigned char **[x]
    bouclesurX
    Values[i] = unsigned char *[y]
    doublebouclesurXetY
    Values[i][j] = unsigned char [z]


    bon, ca a le merite de ne pas etre du code brut, et de peut etre ne pas etre assez clair, mais si tu cherche un peu, avec mes indices, tu va vite comprendre le concept.
    Si ta des questions, n'hesite pas

  3. #3
    Membre du Club
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    Points : 44
    Points
    44
    Par défaut
    Je te remercie tout d'abord pour ta réponse et voici ce que j'ai fait :
    dans un Tableau3D.h (la prof nous demande des les appeler comme ça ) j'ai mis ça :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #ifndef TAB_H
    #define TAB_H
     
    class Tab{
    	private : 
    			unsigned char ***Values;
    			int x;
    			int y;
    			int z;
    	public :
    			Tab(char * filename);
    };
     
    #endif

    Et dans un Tableau3D.cpp j'ai mis ça :
    Code c++ : 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
    #include "Tableau3D.h"
     
    void Tab::Tab()
    {
    	aFile = open("lab3D0.txt")
    	aFile >> xx
    	setX(xx)
    	aFile >> yy
    	setY(yy)
    	aFile >> zz
    	setZ(zz)
    	for ( int X = 1 ; X <= xx ; X++ )
    	{
        	for ( int Y = 1 ; Y <= yy ; Y++ )
        	{
        		for ( int Z = 1 ; Z <= zz ; Z++ )
    			{
    				.....
    			}
        	}
    	}    	
    	aFile>>var
    	Values[i][j][k]=(unsigned char)var
    	afile.close

    Donc si tu pouvais me dire si c'est ça ou pas et sinon j'ai pas compris la fin de ton message lorsque tu me parles du "constructeur de base".
    Je n'ai pas su aussi quoi mettre dans la "triplebouclesurXYZ" .
    Voilà donc si tu pouvais m'aider je te remercie grandement.

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Je me méfie déjà très fortement du recours aux pointeurs lorsqu'ils servent à gérer un tableau d'objet dont la taille est géré dynamiquement.

    Vous comprendrez dés lors que je me méfie encore plus des pointeurs de pointeurs de pointeurs (de...) lorsqu'il s'agit de gérer des tableaux multi-dimentionnels

    En effet, je ne peux m'empêcher de constater que, si on doit représenter Z niveaux contenant Y lignes dont toutes les lignes contiennent X cases, nous avons en réalité besoin d'une collection comprenant X*Y*Z cases

    Il est donc possible d'envisager de n'utiliser qu'un tableau à une seule dimension pour représenter l'ensemble des cases.

    Il "suffit", pour accéder à la case posX de la posY ieme ligne du posZ ieme niveau, lorsque l'on utilise un tableau à une dimension, d'accéder à l'index (posZ*Y*X )+(posY*X )+ posX.

    L'énorme avantage que l'on peut en tirer directement, c'est que nous disposons d'une classe dont le but est, justement, de représenter un tableau à une dimension: la classe vector, disponible dans l'espace de noms std par inclusion du fichier d'en-tête <vector>.

    Nous pourrions donc envisager la création d'une classe proche de
    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
    class Data
    {
        /* nous déclarons une fonction readFile amie de la classe
         *
         * c'est en effet la seule fonction qui doit pouvoir modifier les valeurs
         * des différentes cases ;)
         */
        friend Data readFile(std::string const &);
        public:
            /* le constructeur prend les trois tailles dont on a besoin:
             * - le nombre de niveaux
             * - le nombre de ligne par niveau
             * - le nombre de cases par ligne
             */
           Data(size_t nbreNiveau, size_t nbreLigne, size_t nbreCase):
                maxZ_(nbreNiveau),maxY_(nbreLigne),
                maxX_(nbreCase),data_(nbreNiveau*nbreLigne*nbreCase)
           {
           }
           /* l'ensemble du programme peut souhaiter disposer du caractère
            * se trouvant à la position x, y, z
            */
           char caseAt(int x, int y, int z) const
           {
               return data_[z*(maxX_*maxY_)+(y*maxX_)+x];
           }
           /* il sera sans doute intéressant de vérifier les tailles ;) */
           size_t levelSize() const{return maxZ_;}
           size_t lineSize() const{return maxY_;}
           size_t caseSize() const{return maxX_;}
           size_t totalSize() const{return data_.size();}
        private:
           size_t maxZ_;
           size_t maxY_;
           size_t maxX_;
           std::vector<unsigned char> data_;
    };
    Nous créerions une fonction de lecture du fichier (nomée... readFile, vu que c'est sous ce nom qu'elle est déclarée amie de la classe ) proche de
    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
     
    Data readFile(std::string const & filename)
    {
        /* ouverture du fichier filename */
        std::ifstream ifs(filename.c_str());
        /* nous avons besoin des tailles maxX, maxY et maxZ */
        size_t maxX;
        size_t maxY;
        size_t maxZ;
        /* nous lisons les tailles des différentes dimsensions 
         * Si nous n'y arrivons pas, nous lançons une exception*/
        if(!(ifs>>maxX>>maxY>>maxZ))
            throw BadFileFormat(); // BadFileFormat est à définir par ailleurs ;) 
        /* nous créons notre objet data en lui fournissant les tailles que l'on
         * vient de lire
         */
        Data ret(maxZ,maxY,maxX);
        /* et nous bouclons sur la lecture jusqu'à ce qu'elle soit terminée */
        for(size_t z=0;z<maxZ;++z)
            for(size_t y=0;i<maxY;++y)
                for(size_t x=0;x<maxX;++x)
                    ifs>>ret.data_[(z*maxY*maxX)+(y*maxX)+x];
        /* quand c'est fini, on renvoie l'objet*/
        return ret;
    }
    Et nous utiliserions tout cela sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
        Data tab=readFile("lab3D0.txt");
        /* tout ce que tu veux faire avec tab ;) */
        if (tab.caseAt(2,5,7)=='#')
            /*...*/
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre du Club
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    Points : 44
    Points
    44
    Par défaut
    Merci pour réponse .
    J'ai mis la "class Data" dans un fichier "Tableau.h", la "Data readFile(std::string const & filename)" dans un "Tableau.cpp" (en ayant mis le #include"Tableau.h" en haut) et le main dans un "main.cpp" et j'ai 17 erreurs notamment 7 fois
    "error: `size_t' does not name a type" dans le "Tableau.h" donc je pense ne pas avoir fait tout ça correctement.
    Si tu pouvais m'éclairer

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Seule la première erreur est réellement importante, les autres découlant très certainement de la première

    Ne serait-elle pas proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    error: 'string' is not a member of 'std'
    ou de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    error: 'vector is not a member of 'std'


    Il faut en effet savoir qu'il n'existe aucune classe qui soit connue "directement" du compilateur, et qu'il faut donc inclure le fichier dans lequel la classe sera définie chaque fois que l'on souhaite utiliser une classe fournie par le standard.

    Dans le premier cas (string is not a member of std), le compilateur se plaint de ne pas trouver la définition de la classe string dans l'espace de noms std, et il faut donc inclure le fichier d'en-tête <string>

    Dans le deuxième cas (vector is not a member of std), il se plaint de ne pas trouver la définition de... vector, et il faut donc inclure le fichier d'en-tête <vector>

    Enfin, il pourrait aussi se plaindre de ne pas connaitre ifstream (lorsqu'il regardera à l'implémentation de readFile)... Il faudra donc rajouter le fichier d'en-tete <fstream>

    Une fois que tous ces fichiers d'en-tête seront inclus, le compilateur connaitra l'ensemble des classes fournies par le standard que nous utilisons, et il sera content

    Quant à size_t, il s'agit en réalité d'un alias de type (typedef) de unsigned int (ou est-ce unsigned long ).

    Le fichier dans lequel cet alias de type est défini est inclus de manière indirecte par de très nombreux fichiers, dont <vector>, <string> et même (me semble-t-il) <fstream>...

    tu ne dois donc pas trop t'inquiéter de ces sept erreurs, qui n'en font en réalité qu'une (size_t dois apparaitre... 7 fois dans le code, si on en crois le compilateur ), et qui sera corrigée grâce au jeu des inclusions en cascade
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre du Club
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    Points : 44
    Points
    44
    Par défaut
    Oui c'est vrai je te remercie j'avais complètement oublié les inclusions et leur ajout a fait disparaitre toutes les erreurs sauf celles liées au code en lui même :
    en effet, je ne comprends pas bien cette instruction dans le "main" :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    if (tab.caseAt(2,5,7)=='#')

    Si la case de coordonnées (2,5,7) est un # alors on fait quelque chose. Mais le tableau ne doit pas se remplir automatiquement en lisant le fichier texte ?

    Et aussi, je ne sais pas où et comment définir le BadFileFormat (l'exception).

    Je te remercie par avance du temps que tu me consacres.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Zaza91280 Voir le message
    Oui c'est vrai je te remercie j'avais complètement oublié les inclusions et leur ajout a fait disparaitre toutes les erreurs sauf celles liées au code en lui même :
    en effet, je ne comprends pas bien cette instruction dans le "main" :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    if (tab.caseAt(2,5,7)=='#')

    Si la case de coordonnées (2,5,7) est un # alors on fait quelque chose. Mais le tableau ne doit pas se remplir automatiquement en lisant le fichier texte ?
    Si, le tableau est, effectivement, rempli par la fonction readFile...

    Mais, une fois rempli, je présumes que tu utilisera ces données, non

    En toute logique, l'une des utilisation que tu pourra en faire sera... de tester la valeur d'une case donnée...

    C'est, en gros, ce que je voulais montrer dans la fonction main
    Et aussi, je ne sais pas où et comment définir le BadFileFormat (l'exception).
    Tu devra la définir à l'endroit où elle sera... le plus utile...

    Typiquement, vu que la fonction *risque* de lancer une exception, il faudra entourer l'appel de readFile d'un bloc try...catch.

    On peut donc envisager de définir BadFileFormat dans... le fichier d'en-tête dans lequel est déclarée la fonction readFile
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre du Club
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    Points : 44
    Points
    44
    Par défaut
    Ok merci.
    Oui bien sûr qu'on va utiliser les données de ce tableau. Elles vont servir à afficher le labyrinthe .
    C'est la prochaine étape .

  10. #10
    Membre du Club
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    Points : 44
    Points
    44
    Par défaut
    Voilà le code du try-catch :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     try
        friend Data readFile(std::string const &);
        catch(const BadFileFormat & ...)
        {
        	cerr << "Impossible de lire les dimensions du labyrinthe" << endl;
        }

    Est-ce que c'est comme ça ?

    Si tu as une piste aussi pour afficher le labyrinthe par la suite à partir du tableau je suis preneur (je pense à une boucle for )

  11. #11
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Zaza91280 Voir le message
    Voilà le code du try-catch :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     try
        friend Data readFile(std::string const &);
        catch(const BadFileFormat & ...)
        {
        	cerr << "Impossible de lire les dimensions du labyrinthe" << endl;
        }

    Est-ce que c'est comme ça ?
    Non, un bloc "try catch" se place dans la fonction qui appelle la fonction qui risque de lancer une exception:
    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
    int main()
    {
        try
        {
              Data tab = readFile("fichier.txt"); // c'est elle qui risque de lancer
                                                   // une exception
              /* si on arrive ici, tout s'est bien passé
               * ...
               */
        }
        catch(BadFileFormat & e) // attrapons l'exception, si elle a été lancée
        {
             cout<<"Le format du fichier est incorrect";
        }
        /* ce qui doit être fait, même si l'exception a été lancée 
         * ...
         */
        return 0;
    }
    Si tu as une piste aussi pour afficher le labyrinthe par la suite à partir du tableau je suis preneur (je pense à une boucle for )
    Tu crées une fonction qui prend ta classe Data comme paramètre, et le niveau à afficher, qui boucle sur les différentes cases pour les afficher.

    Elle peut prendre la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void draw(Data const & d, size_t level)
    {
        for(size_t y=0;y<d.lineSize();++y)
        {
            for(size_t x=0;x<d.caseSize();++y)
            {
                std::cout<<d.caseAt(x, y, level);
            }
            std::cout<<endl;
        }
    }
    Et, bien sur, tu peux envisager d'en faire une fonction membre de ta classe Data
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  12. #12
    Membre régulier
    Inscrit en
    Septembre 2007
    Messages
    267
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Septembre 2007
    Messages : 267
    Points : 119
    Points
    119
    Par défaut
    J'suis tout a fait d'accord avec toi Koala pour le vecteur a la place du tableau triple pointeur et utiliser caseAt.

    Par contre j'ai peur qu'au niveau de son prof, lui expliquer chacune de ses tips & trics, il va vite comprendre que ca viens pas vraiment de toi Zaza. A la limite, si c'etait juste le coups du 3*tab vers le vecteur, mais lui expliquer pkoi tu a choisi size_t au lieu de long int, et les multiples autres choses ... Il va se poser des questions quant a l'autenticite de ton travail.

    Enfin bon, en meme temps je ne sais pas ce qu'il (en supposant que ton prof est un mec) vous a deja appris. Alors je te conseil de bien prendre le temps de savoir tout expliquer, et si tu trouve des choses trop tire par les cheveux pour ton niveaux, laisse les tomber !!
    Aller, bon labirinte, et c'est clair, tu peux remercier Koala pour son aide precieuse ^^

  13. #13
    Membre du Club
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    Points : 44
    Points
    44
    Par défaut
    Bien sur que j'en suis reconnaissant .
    Mais en fait on s'est fait chier pour rien parce que là on vient de me dire qu'elle a fourni en fait le code et qu'il faut l'adapter au type tableau à 3 dimensions.
    En fait c'est le code mais pour un labyrinthe à un plateau et nous il contient plusieurs plateaux .
    Je t'ai emmerdé pour rien koala je suis désolé (enfin j'aurais peut être besoin d'aide mais pas pour tout faire de A à Z).

    Encore désolé .

Discussions similaires

  1. [Débutant] comment remplir un tableau sous excel avec des données de DGV?
    Par spring.time dans le forum VB.NET
    Réponses: 6
    Dernier message: 26/10/2012, 20h36
  2. Réponses: 8
    Dernier message: 22/06/2009, 18h06
  3. Réponses: 3
    Dernier message: 16/12/2006, 12h59
  4. Charger un module automatiquement avec des options debian
    Par ZiMo dans le forum Administration système
    Réponses: 4
    Dernier message: 22/12/2005, 14h22
  5. Réponses: 4
    Dernier message: 07/11/2005, 15h54

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