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 :

Création de matrice.


Sujet :

C++

  1. #1
    Candidat au Club
    Inscrit en
    Décembre 2008
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 6
    Points : 4
    Points
    4
    Par défaut Création de matrice.
    Bonjours à tous,
    Je suis un débutant en C++.
    J'ai un fichier texte contenant un titre suivi de valeurs entières.
    Je doit lire le fichier et stocker les valeurs dans une matrice.

    Comment me conseillez-vous de m'y prendre ?

    J'ai ouvert le fichier, mais ça coince avec la méthode getline( , , ,)
    pouvez vous m'expliquer comment le getline fonctionne?
    Dois-je convertir les valeurs en entier avant de les stocker dans la matrice ou la librairie <string> s'en chargera?
    Exsiste-t-il un container ou une librairie qui gère les matrices?
    Je commence avec des matrice statiques mais je voudrais le faire avec des matrices dynamique (Tableaux dynamiques). Comment doit-on s'y prendre?

    Merci.

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 897
    Points : 219 633
    Points
    219 633
    Billets dans le blog
    125
    Par défaut
    Si tu n'est pas trop réticent à l'anglais je te conseille un site : http://www.cplusplus.com/
    Notamment cette page ( pour aujourd'hui ) : http://www.cplusplus.com/reference/iostream/ifstream/

    Mince , je suis parti un peu vite , je te conseille d'utiliser la lecture de fichier via la STL , soit avec un ifstream , et non l'ouverture de fichier à la fopen ( ça vaut pour le C ) , mais ce qu'on a avec le c++ c'est mieux

    getline , prend , un tableau de char ( char* ; soit ta chaine de caractère ) , et la taille de ce que tu veux lire. ( Si tu met une taille plus grande que la taille de la ligne il s'arrête on retour de chariot )
    ( Tu peux aussi spécifier un délimiteur , pour qu'il s'arrête dès qu'il trouve celui ci )

    Après avec ton fichier ( ifstream ) , en C++ tu pourra lire élément par élément avec l'operateur >> . Comme pour lire sur cin ( je pense que ça tu as fais )
    Et donc grace à cet opérateur tu peux directement remplir tes variables.

    J'ai vu sur ce site , un gars qui a fait grace au conteneur vector une class pour faire les matrices , génériques . Il a fait du bon travail , mais je conseillerai encore un tableau ( préférable dynamique ) ,ou un vector. Dépend si tu lis une matrice ou juste des valeurs.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut, et bienvenue sur le forum.

    Déjà, il faut bien comprendre à quoi sert la classe std::string: elle ne sert qu'à représenter des chaines de caractères, et à fournir des méthodes adaptées à leur gestion.

    Une fois que tu as cela en tête, tu comprend normalement que la classe std::string n'est clairement pas destinée à servir dans une matrice regroupant des valeurs entières

    Maintenant, il peut être utile (nécessaire/indispensable) de se poser la question de savoir si tu peux avoir une confiance absolue dans le fichier que tu lis, ou non.

    Ce que je veux dire par là, c'est: pose toi la question de savoir si tu peux te contenter de lire les informations sans les vérifier, ou si tu dois - d'une manière ou d'une autre - t'assurer que les informations lues sont cohérentes en type et ou en nombre.

    La deuxième question à te poser est sans doute de savoir si tu auras affaire à une matrice "pleine" ou non.

    J'entends par là de te poser la question de s'avoir s'il y a toujours le même nombre de colonne par ligne, ou est il possible qu'il y ai des colonnes non indiquées dans le fichier.

    Dans le cas le plus simple à gérer, tu n'a pas besoin de vérifier la cohérence des données lue d'une autre manière que de t'assurer - éventuellement - que les données lues sont dans une plage de valeurs donnée, et tu pourrais considérer ta matrice comme étant un vecteur contenant lignes*colonnes éléments.
    tu pourrais donc te "limiter" à quelque chose d'aussi simple que
    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
    class Matrix
    {
        public:
            Matrix(size_t mcols, size_t mrows):mcols(mcols),mrows(mrows),tab()
            {
            }
            /** fonction de récupération de la matrice dans le fichier
               * in: nom du fichier à lire
               */
            void read(const std::string& filename)
            {
                /* par sécurité, donnons nous l'occasion de gérer
                 * les exceptions qui pourraient survenir
                 */
                try
                {
                    /* ouverture du fichier en lecture */
                    std::ifstream ifs(filename.c_str());
                    if(!ifs)
                        throw std::ifstream::failbit;
                    for(size_t i=0;i<mrow;++i)
                    {
                        for(size_t j=0;j<mcols;++j)
                        {
                            int val;
                            ifs>>val;
                            /* éventuellement, nous lançons une exception si 
                             * la valeur n'est pas dans une plage donnée
                             */
                            if(val<0 || val>MAX) // MAX est défini quelque part
                                                 // comme étant la valeur maximale
                                                 // de la plage admise
                                 throw std::out_of_range("valeurs hors limites");
                            tab.push_back(val);
                       }
                    }
                    catch(std::exception & e)
                    {
                        std::cout<<e.what();
                        throw e;
                    }
                }
                size_t item(size_t row, size_t col)
                {
                    /* lance une exception si l'index row ou l'index col
                     * ne correspond pas au nombre de ligne ou de colonne
                     */
                   if(row>=mrows)
                       throw std::out_of_range("indice de ligne hors limites");
                   if(col>=mcols)
                       throw std::out_of_range("indice de colonne hors limites");
                   return tab[row*mcols+col];
                }
        private:
            size_t mrows; // nombre de lignes
            size_t mcols;  // nombre de colonnes
            std::vector<size_t> tab; // le vecteur
    };
    Dans les cas les plus complexes, il faut t'assurer que les données lues sont cohérentes (qu'il n'y a pas une valeur sous la forme de (chaine de)caractère(s) ou de réels, par exemple) et le nombre de colonnes par ligne n'est pas constant.

    Il sera alors sans doute utile de créer une abstraction de la notion de "ligne" de matrice et une abstraction de la notion de matrice elle-même, voire, de prévoir une analyse lexicale (et peut être syntaxique) des données.

    Et, dans ce cas, il n'est pas exclu que tu te trouve, effectivement, face à la nécessité de lire les informations lignes par lignes (avec std::getline), et de convertir ces informations en passant - plus que vraisemblablement - par un objet de type std::stringstream avant de remplir chaque ligne de ta matrice.

    Mais là, nous sommes devant tellement de possibilités qu'il nous faudra quelques informations supplémentaires pour arriver à t'orienter vers la solution "la moins mauvaise" (à défaut de trouver la meilleure )

  4. #4
    Candidat au Club
    Inscrit en
    Décembre 2008
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 6
    Points : 4
    Points
    4
    Par défaut Autres questions
    Le programme que je réalise doit être le plus optimal possible en terme de complexité. Que me conseillez-vous : faire des vecteurs de vecteurs avec
    la directive de compilation <vector> ou de faire une allocation dynamique de vecteurs en utilisant new et delete[]?

    Quand j'écris les données de la matrice dans un fichier texte, toutes les valeurs sont décalées. N'existerait-il pas une façon de faire pour les avoir toutes alignées en définissant une plage d'écriture par valeur?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Pour moi, tu va chercher beaucoup de difficulté là où il n'y aurait pas lieu d'en trouver.

    Et il y a, en outre, pas mal de place pour le progrès

    Je vais donc commencer par faire quelques remarque, je t'indiquerai la manière de les prendre en compte juste après .

    La première remarque est qu'il est toujours préférable d'utiliser les possibilités issues du C++ plutôt que l'équivalent "C style"...

    Cela signifie que, de manière générale, tu auras toujours intérêt à utiliser la std::string plutôt qu'un tableau de caractères char* ou char[taille], et que tu aura sans doute largement intérêt à utiliser un std::vector<int> plutôt qu'un int* (ou un int**)

    En ce qui concerne les chaines de caractères, s'il se fait que tu dois récupérer une chaine "C style" (pour l'ouverture d'un fichier, par exemple), ce n'est pas une raison pour préférer le char[], car tu peux la récupérer grace à la méthode c_str()

    La deuxième remarque est qu'il est souvent préférable de travailler en respectant le principe du RAII (Ressource Aquisition Is Initialisation, ou, si tu préfères en français, l'acquisition de ressources sert d'initialisation).

    C'est particulièrement vrai pour les flux de fichier.

    Ainsi, plutôt que de travailler en deux temps sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::ifstream file;
    file.open(filename.c_str());
    il est souvent préférable de donner directement le nom du fichier à ouvrir dans le constructeur, et de se contenter d'un "simple"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::ifstream file(filename.c_str());
    Si tu as un doute sur l'existence du fichier à ouvrir, le plus facile est sans doute de lancer une exception si la variable est invalide, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    if(!file)
        throw l_exception_choisie;
    Evidemment, cela signifie que, l'appel de la fonction qui risque de lancer une exception devrait se trouver dans un bloc try... catch, soit parce que la fonction appelante peut gérer l'exception, soit pour la faire remonter la pile d'appel

    Ensuite, comme je l'ai indiqué plus haut, il devient rapidement ingérable de devoir gérer une matrice dans la représentation "classique" que l'on peut en avoir (à savoir un tableau composé de "lignes" et de "colonnes").

    Si, pour chaque ligne, il y a systématiquement le même nombre de colonnes, le mieux est de gérer cette matrice sous la forme d'un tableau dont le nombre d'élément est (nombre_de_lignes * nombre_de_colones) et d'utiliser la formule (nombre_de_colonnes*index_ligne_recherchée + index_colonne_rechercée) pour accéder à un élément particulier.

    Cette approche présente l'énorme avantage de... rendre l'utlisation d'un "simple" vecteur d'entier tout à fait naturelle et de lui donner une facilité extrême

    Visiblement, tu envisage de travailler de manière systématique avec des matrices carrées (vu que tu n'indiques qu'un seul nombre, qui sert à la fois de nombre de lignes et de nombre de colonnes)...

    Quoi qu'il en soit, du fait que le nombre de lignes et de colonnes est disponible dans le fichier, il semble "naturel" de prévoir une gestion "dynamique" (même si elle est prise en charge par une classe particulière) du nombre d'éléments qui composent la matrice.

    Si tu dois commencer à jouer avec des new[] et des delete[], tu va perdre un maximum de temps et courir un maximum de risques pour, seulement, arriver à gérer correctement la mémoire, ce qui plaide, une fois encore, pour l'utilisation de la classe vector

    Par contre, le fait que tu récupère le nombre de lignes et de colonnes dont est composée ta matrice fait qu'il deviendra finalement plus logique de travailler avec deux boucles imbriquées (la première gardant le nombre de lignes lues et la seconde s'occupant de compter le nombre de colonnes lue dans la ligne) pour la lecture du fichier que de travailler sur une boucle réagissant sur... une erreur de lecture (eof, en l'occurence), et ce, d'autant plus que, lorsque eof est activé, c'est... que tu as déjà une lecture qui n'a pas pu s'effectuer

    Tout cela pour dire qu'il y a vraiment moyen de simplifier énormément la fonction de lecture, sous une forme finalement fort 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
    38
    39
    40
    41
    42
    /** fonction de lecture de la matrice dans un fichier
       * @ in-out: un vecteur contenant les éléments de la matrice
       *           un entier représentant le nombre de lignes et de colonnes
       * @ in : le nom du fichier à lire
       * @ throw: std::invalid_argument si le fichier n'existe pas
       *          std::runtime_error si une erreur survient lors de  la lecture
       *          du fichier
       */
    void readFile(std::vector<int>& matrix, int& size, const std::string& filename)
    {
        /* ouvrons le fichier en lecture */
        std::ifstream file(filename.c_str());
        /* si le fichier n'est pas ouvert, c'est pas bon :-P */
        if(!file)
            throw invalid_argument("nom de fichier incorrect");
        /* nous voulons récupérer la première ligne comme "titre" */
        std::string titre;
        std::getline(file,titre);
        /* affichons la pour nous rassurer */
        std::cout<<titre<<std::endl;
        /* récupérons le nombre de lignes et de colonnes */
        file>>size;
        /* et affichons le */
        std::cout<<size<<" lignes et "<<size<<" colonnes seront lues"<<std::endl;
        /* utilisons une boucle incrémentale pour compter les lignes
         */
        for(int lignes=0;lignes<size;++lignes)
        {
            /* qui contient une boucle pour chaque colonne de la ligne */
            for(int colonnes=0;colonnes<size;++colonnes)
            {
                /* qui lit l'élément, lance une exception si la lecture échoue
                 * et insère l'élément dans la matrice
                 */
                int elem;
                if(!file>>elem)
                    throw std::runtime_error("erreur de lecture de l'element");
                matrix.push_back(elem);
           }
        }
        /* voilà, c'est fini :D */
    }
    En outre, il faut savoir que la fonction main() renvoie d'office une valeur de type int au système d'exploitation.

    Il existe normalement trois valeurs possibles, mais seule les deux premières sont utilisées sous windows:
    • 0 l'application s'est correctement terminée
    • 1 l'application s'est terminée sur une erreur
    • 2 l'application s'est terminée sur un avertissement (unixoides uniquement)


    Il n'est en outre pas nécessaire de préciser le type void dans la liste d'arguments si la fonction n'en nécessite aucun (une autre signature "classique" étant int main(int argc, char *argv[]) )
    L'appel de cette fonction pourrait se faire sous une forme 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
    int main()
    {
        /* le vector qui contiendra les éléments de la matrice*/
        std::vector<int> matrix;
        /* le nombre de lignes et de colonnes (nous considérons une matrice
         * carrée
         */
        int size;
        /* indiquons le fichier à lire "en dur" (il est facile de modifier cela
         * pour laisser le choix à l'utilisateur ;)
         */
        try
        {
            readFile(matrix, size,"ficier.txt");
        }
        catch(std::exception& e)
        {
            std::cout<<e.what();
            return 1;
        }
        return 0;
    }

  6. #6
    Candidat au Club
    Inscrit en
    Décembre 2008
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 6
    Points : 4
    Points
    4
    Par défaut
    Bonjour,

    J'avance petit à petit.
    Je vous remercie pour vos conseils et explications.

    J'ai fait une partie de mon programme(ma classe matrice).
    Cette partie devra être utilisée par deux autres programmes main().
    Pour ne pas tout réécrire, je voudrais mettre ma classe matice dans un
    fichier à part (faire un point h) et mettre mon main() dans autre fichier.

    Comment dois-je m'y prendre ?

    Merci.

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Bonjour et bienvenu,
    Tu trouveras des infos dans cette entrée de la FAQ et si tu utilises des templates, fais attention aussi à ça.

Discussions similaires

  1. Création image matrice niveau de gris
    Par juliefournet dans le forum Calcul scientifique
    Réponses: 5
    Dernier message: 03/05/2013, 18h01
  2. Création de Matrice dynamique
    Par cobra150 dans le forum Débuter avec Java
    Réponses: 1
    Dernier message: 16/04/2012, 15h48
  3. création de matrice
    Par vanvan2583 dans le forum Fortran
    Réponses: 4
    Dernier message: 14/03/2012, 21h36
  4. [Débutant] Création de Matrice 123. . .
    Par Mat32 dans le forum MATLAB
    Réponses: 8
    Dernier message: 04/10/2009, 12h54
  5. Création de matrice
    Par bg56 dans le forum MATLAB
    Réponses: 3
    Dernier message: 19/11/2007, 11h16

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