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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    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 éclairé
    Inscrit en
    Septembre 2007
    Messages
    267
    Détails du profil
    Informations personnelles :
    Âge : 38

    Informations forums :
    Inscription : Septembre 2007
    Messages : 267
    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 confirmé
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    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
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    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 confirmé
    Inscrit en
    Janvier 2010
    Messages
    116
    Détails du profil
    Informations forums :
    Inscription : Janvier 2010
    Messages : 116
    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
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    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

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