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 :

Découpage d'une chaine de caractères avec istringstream : segmentation fault.


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2013
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2013
    Messages : 41
    Par défaut Découpage d'une chaine de caractères avec istringstream : segmentation fault.
    Bonjour à tous.

    J'essaie de créer une fonction qui récupère des coordonnées dans un fichier texte. Le fichier texte étant conçu de cette manière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    #{
    N1 -nombre- -nombre- -nombre- -nombre-
    N2 -nombre- -nombre- -nombre- -nombre-
    [...]
    Nx -nombre- -nombre- -nombre- -nombre-
    #}
    Je dois donc récupérer tout les nombres, bien entendu en ignorant la première et dernière ligne. Chaque ligne représentant donc les coordonnées des deux points d'un segments. J'ai donc rédigé la procédure suivante :
    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
     
    void setDataTable(float points[MAX][2] , string file)
    {
        ifstream f(file.c_str(), ios::in);
        string line, str;
        vector<string> result;
        int j=0;
        if (f)
        {
            while (! f.eof())
            {
                getline(f,line);
                istringstream iss(line);
                while (getline(iss, str, ' '))
                {
                    result.push_back(str);
                }
     
                for(int i=0; i < result.size(); i++)
                {
                    if (i == 1) points[j][0] = atof(result[i].c_str());
                    if (i == 2) points[j][1] = atof(result[i].c_str());
                    if (i == 3) points[j+1][0] = atof(result[i].c_str());
                    if (i == 4)
                    {
                        points[j+1][1] = atof(result[i].c_str());
                        j = j+2;
                    }
                }
     
            }
        }
        else
        {
            cerr << "setDataTable : can't read " << file << "." << endl;
        }
        cout << "Fin fonction setDataTable" << endl;
        f.close();
    }
    L'ennui, c'est que j'arrête pas d'avoir des segmentation faults, et j'arrive vraiment pas à résoudre ce problème. Je dois avoir raté quelque chose avec la lecture du fichier ou du istringstream. Une idée ?

    Merci d'avance pour votre réponse.

  2. #2
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    pour commencer, ce n'est pas while (f.eof()), mais while (getline(file, line)).
    En effet, eof indique si la derniere erreur est due à un eof, et getline peut ne pas marcher.

    on n'écrit pas ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
                for(int i=0; i < result.size(); i++)
                {
                    if (i == 1) points[j][0] = atof(result[i].c_str());
                    if (i == 2) points[j][1] = atof(result[i].c_str());
                    if (i == 3) points[j+1][0] = atof(result[i].c_str());
                    if (i == 4)
                    {
                        points[j+1][1] = atof(result[i].c_str());
                        j = j+2;
                    }
                }
    Il y a un peu mieux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    for(int i=0; i < result.size(); i++) {
        switch (i){
            case 1: points[j][0] = atof(result[i].c_str()); break;
            case 2: points[j][1] = atof(result[i].c_str()); break;
            case 3: points[j+1][0] = atof(result[i].c_str()); break;
            case 4:
                points[j+1][1] = atof(result[i].c_str());
                j = j+2;
                break;
        }
    }
    Et franchement plus clair:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    {
        points[j][0] = atof(result[1].c_str());
        points[j][1] = atof(result[2].c_str());
        points[j+1][0] = atof(result[3].c_str());
        points[j+1][1] = atof(result[4].c_str());
        j = j+2;
    }
    Et la, subitement, tout devient clair.
    un vector commence à 0.

    Et tu peux même faire beaucoup mieux, en ne passant pas par result, mais directement par l'opérateur >> de istream.

    Autres remarques:
    • Controle l'erreur plutot que la validité: tu pourras quitter tout de suite, et le reste du code sera moins indenté. Avec cinq ressources, tu verras clairement la différence.
    • Il est inutile de fermer un stream déclaré en variable locale, le destructeur le fait pour toi.
    • Personnellement, je remplacerais la variable points par un vector<point<float>>, en définissant proprement point<float>.
      Après tout, pourquoi utiliser deux cases d'un tableau pour désigner un objet unique (un point)?


    Voici comment j'écrirai ta fonction (en gardant ton interface).

    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
     void setDataTable(float points[MAX][2] , string filename) {
        ifstream file(filename.c_str();
     
        if (!file) {
            cerr << "setDataTable : can't read " << filename << "." << endl;
    		throw std::runtime_error("file not opened: "+filename);
    	}
     
        string line;
        int j=0;
    	while (getline(file,line)) {
    		istringstream iss(line);
    		iss >> points[j][0] >> points[j][1] >> points[j+1][0] >> points[j+1][1]
    		j+=2
        }
        cout << "Fin fonction setDataTable" << endl;
    }

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2013
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2013
    Messages : 41
    Par défaut
    Je viens d'essayer ton programme. On dirait que c'est pas ça : je débouche encore sur une segmentation fault. :/

    Par contre en effet, le code est plus lisible et bien plus propre.

  4. #4
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Avec un code clair, tu vois mieux que le problème ne vient pas de la.

    Pour moi, la cause, c'est d'avoir un tableau (dont les tailles ne sont pas spécifiables) en argument d'une fonction.

  5. #5
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2013
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2013
    Messages : 41
    Par défaut
    Bon, j'ai essayé de refaire avec une classe point. Ça me donne le code suivant.

    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
     
    void setDataTable(point p[MAX] , string filename)
    {
       ifstream file(filename.c_str());
       string str;
       vector<string> result;
     
       if (!file)
       {
           cerr << "setDataTable : can't read " << filename << "." << endl;
           throw std::runtime_error("file not opened: "+ filename);
       }
     
       string line;
       int j=0;
       while (getline(file,line))
       {
           istringstream iss(line);
           while(getline(iss,str))
           {
               result.push_back(str);
           }
           p[j].setX(atof(result[1].c_str()));
           p[j].setY(atof(result[2].c_str()));
           p[j+1].setX(atof(result[3].c_str()));
           p[j+1].setY(atof(result[4].c_str()));
           j=j+2;
       }
       cout << "Fin fonction setDataTable" << endl;
     
    }
    J'ai encore une segmentation fault (décidément, quand ça veut pas, ça veut pas). Sachant que je suis obligé de mettre un tableau en paramètre je crois, sinon je vois pas comment faire. Je pourrais essayer avec un vector remarque. Une idée ,

  6. #6
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Pourquoi tu as remis atof?
    Cette fonction comprends un "undefined behaviour" quand la donnée n'est pas un float.
    Ma solution ignore les blancs, les retours chariots, les tabulations, etc.

    supposant la classe Point, ta fonction pourrait avoir pour signature void loadDataTable(std::string const& filename, std::vector<point>& points).
    Voire mieux, si tu utilises les itérateurs d'insertion (comme std::insert_iterator)

    En reprenant l'interface de std::copy, ca donnerait
    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
    template<class OutputIt>
    OutputIt loadDataTable(std::string const& filename, OutputIt output) {
        ifstream file(filename.c_str();
     
        if (!file) {
            throw std::runtime_error("file not opened: "+filename);
        }
     
        string line;
        while (getline(file,line)) {
            istringstream iss(line);
            point p1, p2;
            iss >> p1.x >> p1.y >> p2.x >> p2.y;
            *(output++) = p1;
            *(output++) = p2;
        }
        return output;
    }
    Et la, tu n'as même plus besoin de savoir que la classe est un vector, une liste ou un set. (tant qu'elle à une fonction insert compatible avec point).

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

Discussions similaires

  1. Découpage d'une chaine de caractères
    Par fab3131 dans le forum MFC
    Réponses: 2
    Dernier message: 08/04/2006, 16h46
  2. Dégradé sur une chaine de caractères avec 3 a 4 couleurs
    Par avogadro dans le forum Composants VCL
    Réponses: 6
    Dernier message: 31/03/2006, 13h21
  3. Lecture d'une chaine de caractère avec fgets
    Par mayoouketchup dans le forum Langage
    Réponses: 9
    Dernier message: 22/12/2005, 16h17
  4. découpage d'une chaine de caractère
    Par lamojuli dans le forum ASP
    Réponses: 4
    Dernier message: 13/05/2004, 15h00
  5. Réponses: 2
    Dernier message: 06/12/2002, 07h50

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