Search code examples
c++functionstructread-writevisual-c++-2008-express

write/read struct to file using functions , Visual C++ 2008 express


I've made three files using Visual C++ 2008 express for a text based RPG game. Before I really dive into the whole thing I want to get the basics ironed out: new game, save game, continue game, quit game. So far I have the make a character section (in this case find a weapon) and quit game all ironed out. I'm stuck on how to pass the weapon stats from a struct to a save file. I appear to pass the members of the struct without issue and check the file to find "junk": Ì and -858993460 in place of my values.

How should I go about fixing my save_game and continue_game functions? I've done a lot of research trying to figure this out and nothing I've tried seems to help.

Here's the important pieces of the code:

struct player_character
{
char type;
int damage;
int stability;
};

void save_game(player_character& pc, ofstream &save);
void continue_game(player_character& pc, ifstream &get);

int main()
{   
player_character pc;
ofstream save;
ifstream get;

//rest of main() goes here.

//pause screen
system("pause");
return 0;
}

//rest of functions go here.

void save_game(player_character &pc, ofstream &save_data) 
{
save_data.open  ("save.dat", ios::binary);
    if (save_data.is_open())
    {
    save_data << "pc.type = " << pc.type << endl;
    save_data << "pc.damage = " << pc.damage << endl;
    save_data << "pc.stability = " << pc.stability << endl;
                //doesn't work
    //save_data.write(reinterpret_cast<char*>(&pc), sizeof(pc));
    save_data.close();
    }
    else
    {
    cout << " Error. Unable to open file.";
    }
}

void continue_game(player_character &pc, ifstream &get_data) 
{
get_data.open("save.dat");
if (get_data.is_open())
    {
                //doesn't work
    //get.read(reinterpret_cast<char*>(&pc), sizeof(pc));
    get.close();
    }
    else
    {
    cout << " Error. Unable to open file.";
    }
}

Thanks for the reponse. I'm trying the following revisions. The continue_game function appears to work. I recieve no errors (yet). When I select save after making a character I recieve the following error: Unhandled exception at 0x69197a28 in Undone.exe: 0xC0000005: Access violation reading location 0xffffffcc.

Google shows it as some sort of Windows issue.

Why is my function causing this error?

void save_game(ofstream &save, player_character const &pc) 
{
save.open  ("save.dat");
    if (save.is_open())
    {
    save.write(reinterpret_cast<char const *>(pc.type), sizeof pc.type); 
    save.write(reinterpret_cast<char const *>(pc.damage), sizeof pc.damage); 
    save.write(reinterpret_cast<char const *>(pc.stability), sizeof pc.stability); 
    save.close();
    }
    else
    {
    cout << " Error. Unable to open file.";
    }
}

int continue_game(ifstream &get) 
{
if (!get.read(reinterpret_cast<char *>(&pc.type), sizeof pc.type)) { /* error */ } 
if (!get.read(reinterpret_cast<char *>(&pc.damage), sizeof pc.damage)) { /* error */ } 
if (!get.read(reinterpret_cast<char *>(&pc.stability), sizeof pc.stability)) { /* error */ } 

return pc.type;
return pc.damage;
return pc.stability;
}

I've changed the save_game and continue_game code and included it here. I also collected the debugger and autos output (small version of autos, not all seven pages). Apparently my values are not being evaluated in save_game so continue_game has nothing to work with and doesn't cause errors.

Here's the code and debugger/autos printouts:

int save_game(ofstream &save, player_character& pc) 
{
save.open  ("save.dat", ios::binary);
if (save.is_open())
{
//the error hits here:
    save.write(reinterpret_cast<char const *>(pc.type), sizeof pc.type); 
    save.write(reinterpret_cast<char const *>(pc.damage), sizeof pc.damage); 
    save.write(reinterpret_cast<char const *>(pc.stability), sizeof pc.stability); 
    save.close();
}
else
{
    cout << " Error. Unable to open file.";
}
return pc.type;
return pc.damage;
return pc.stability;
}

int continue_game(ifstream &get, player_character& pc)
{
get.open  ("save.dat", ios::binary);
if (get.is_open())
{
    if (!get.read(reinterpret_cast<char *>(&pc.type), sizeof pc.type)) { /* error */ } 
    if (!get.read(reinterpret_cast<char *>(&pc.damage), sizeof pc.damage)) { /* error */ } 
    if (!get.read(reinterpret_cast<char *>(&pc.stability), sizeof pc.stability)) { /* error */ } 
    get.close();
}
else
{
    cout << " Error. Unable to open file.";
}
return pc.type;
return pc.damage;
return pc.stability;
}

Debugger Output Window: First-chance exception at 0x644e7a28 in Undone.exe: 0xC0000005: Access violation reading location 0xffffffcc. Unhandled exception at 0x644e7a28 in Undone.exe: 0xC0000005: Access violation reading location 0xffffffcc.

Autos: - pc {type='Ì' damage=-858993460 stability=-858993460 } player_character & type -52 'Ì' char damage -858993460 int stability -858993460 int pc.type -52 'Ì' char - save {_Filebuffer={...} } std::basic_ofstream > & + std::basic_ostream > {...} std::basic_ostream > + _Filebuffer {_Pcvt=0x00000000 _Mychar='Ì' _Wrotesome=false ...} std::basic_filebuf >


Well I'vve managed to make some progress. I discovered I needed to place arguments into my main_menu function (mind you I'm not taking about the main() function, but one I made) so that they would be passed on to my save_game function. I was also able to stop the access error by adding an & into my write function. So this:

save.write(reinterpret_cast<char const *>(&pc.type), sizeof pc.type); 
save.write(reinterpret_cast<char const *>(&pc.damage), sizeof pc.damage); 
save.write(reinterpret_cast<char const *>(&pc.stability), sizeof pc.stability); 

instead of:

save.write(reinterpret_cast<char const *>(pc.type), sizeof pc.type); 
save.write(reinterpret_cast<char const *>(pc.damage), sizeof pc.damage); 
save.write(reinterpret_cast<char const *>(pc.stability), sizeof pc.stability); 

The savve_game code still doesn't work properly yet when it comes to putting data into a file but it does printout to the screen.


Solution

  • It looks like I figured it out! Here's what I've come up with: struct in array...and it appears to work just fine.

    void save_game(fstream& file, player_type& pc)
    {
        file.open("save.dat");
        if (file.is_open())
            for (int i = 0; i < 1; i++)
            {
                file << pc.w_name << endl;
                file << pc.d_rate << endl;
                file << pc.s_rate << endl;
                file.close();
            }
            else
                cout << " Error. Unable to open file.";
        menu(pc);
    }//end save function
    
    void continue_game(fstream& file, player_type player[])
    {
        file.open("save.dat");
        if (file.is_open())
            for (int i = 0; i < 1; i++)
            {
                file >> player[i].w_name;
                file >> player[i].d_rate;
                file >> player[i].s_rate;
                file.close();
            }                   
            else
                cout << " Error. Unable to open file.";
        for (int i = 0; i < 1; i++)
        {
            cout << "You are continuing the game with the following weapon: " << player[i].w_name << endl;
            cout << "Which has a damage rating of " << player[i].d_rate << " and a stability rating of " << player[i].s_rate << endl; 
        }
        cout << endl;
        menu(pc);
    }//end continue_game