dimanche 10 avril 2022

Segmentation fault reading data from file in binary mode

I built a small piece of code which creates some objects, read the objects already saved in a file and appends new objects if they don't belong to the file records. When I run the app the first time the objects are appended to the file. The second time I run the app, I get a segmentation fault when I try to print or save the object on a list. The problem happens in the function openFileRead(). The temporary Player object is created from the default constructor and I try to assign to it the values of the file stream.read((char *) &p,sizeof(Player)) and then save it on the list PlayerFileList.push_back(p);. Here the fault happens. The object isn't correctly assigned to the record in the file, I suppose, since if I try to send it's values to stdout, before saving it in the list, I also get the fault. I think that the operator== isn't working. I didn't overloaded this operator since I don't have static or pointers allocated members in Player object. So, I don't understand this weird the fault. The code is:

header:

    #include <iostream>
    #include <string>
    #include <vector>
    #include <fstream> 
    
    using namespace std;
    
    class Player
    {
    
        private:
            string PlayerName;
            int PlayerScore;
        public:
            Player();       
            Player(string name, int s);     
            ~Player() {};       
            string getPlayerName()  {return PlayerName;}
            int getPlayerScore() {return PlayerScore;}
            void setPlayerName(string name){PlayerName = name;}
            void setPlayerScore(int score){PlayerScore = score;}          
            bool operator!=(const Player &) const;     
            bool operator==( const Player &) const;          
    };
    
    class Game
    {
    
        private:
            Player NewPlayer;
            int NPlayers;
            int NFilePlayers;       
            vector <Player> PlayerList;
            fstream stream2;
            ifstream stream;
            vector <Player> PlayerFileList;
        
            
        public:
            Game();
            ~Game();
            void setNewPlayer(string, int); 
            void resizePlayerList();
            void PrintList();
            void openFileRead();
            void openFileWrite();
            void closeFile();
            void writeToFile();
            friend std::ostream& operator<< (std::ostream&, Player);
    };

class file:

    #include <iostream>
    #include <string>
    #include <cstring>
    #include <memory>
    #include <fstream> 
    #include <algorithm>
    #include <vector>
    #include "I.h"
    
    using namespace std;
        
    Player::Player()
    {
        PlayerName = "No Name";
        PlayerScore = 0;
    }
    
    Player::Player(string name, int s)
    {
        PlayerName = name;
        PlayerScore = s;    
    }
    
    bool Player::operator==(const Player &player) const
    {
        return( (PlayerName == player.PlayerName) && ( PlayerScore == player.PlayerScore) );
    }
    
    
    bool Player::operator!=(const Player &player) const
    {
        cout << PlayerName << player.PlayerName << " "<< PlayerScore  << player.PlayerScore << endl;
        return( (PlayerName != player.PlayerName) ||  (PlayerScore != player.PlayerScore) );
    }
    
    std::ostream& operator<< (std::ostream& stream, Player player)
    {
        stream << player.getPlayerName() << " " <<  player.getPlayerScore() << endl;
        return stream;
    }
    
    Game::Game() 
    {
        NPlayers = 0;   
    };
    
    Game::~Game() {};
    
    void Game::setNewPlayer(string str, int scr)
    {
        NewPlayer = Player(str, scr);   
        resizePlayerList();         
    }
    
    
    void Game::resizePlayerList() {
       
        if(NewPlayer.getPlayerName() != "No Name")
        {
                PlayerList.push_back (NewPlayer);
                    NPlayers++;
            }    
    }
    
    
    void Game::PrintList()
    {
        
        for(int i= 0; i < NPlayers; i++)
        {
                
            cout << PlayerList[i] << endl;  
        }
    
    }
    
    void Game::openFileWrite()
    {
        stream2.open("Players.dat", ios::app | ios::in | ios::binary);
        if (!stream2) 
        {
            cerr << "File could not be opened to write" << endl;
             exit(EXIT_FAILURE);            
        }   
    }
    
    void Game::openFileRead()
    {
        stream.open("Players.dat", ios::in | ios::out | ios::app |ios::binary );
        if (!stream) 
        {
            cerr << "File could not be opened to read" << endl;
             exit(EXIT_FAILURE);            
        }   
        stream.seekg (0, stream.end);
        int length = stream.tellg()/sizeof(Player); 
        stream.seekg (0, stream.beg);
        Player p;
        for(int  i= 0; i < length; i++)
        {   
            stream.read((char *) &p,sizeof(Player));        
            PlayerFileList.push_back(p);        
        }
        NFilePlayers = PlayerFileList.size();   
        
        for(int i= 0; i <NFilePlayers; i++)
        {
                
            cout << PlayerFileList[i] << endl;  
        }
        stream.close();
    }   
    
    void Game::writeToFile()
    {
        vector <Player> vec;    
        Player p;
        for (int i=0; i < NPlayers; i++)    
        {
        
            if (std::find(PlayerFileList.begin(), PlayerFileList.end(), PlayerList[i]) == PlayerFileList.end())
            {
                    stream2.write((const char *)&PlayerList[i],sizeof(Player));             
                }
            
            }
    }

main:

    #include <iostream>
    #include <string>
    #include "I.h"
    
    using namespace std;
    
    int main()
    {
        Game NewGame;
        NewGame.openFileRead();
        NewGame.setNewPlayer("Peter",20);
        NewGame.setNewPlayer("Someone Someone",30);
        NewGame.setNewPlayer("Someone else",40);
        NewGame.PrintList();
        NewGame.openFileWrite();
        NewGame.writeToFile();
        return 0;
    }

If the problem is related with the std::string class and I still want to write the file in binary mode since each field object can contain several member data (I just used 2 for illustration) how can I do that? No book explains that, at least, none I ever read.

Aucun commentaire:

Enregistrer un commentaire