I/O with files

Hello, geeks!

I'm having a code that saves data of an object into a file looks like this...

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
//This is player.cpp
#include "main.cpp"

using namespace std;

int main()
{
	board p1,p2;
	fstream f, f1;
	
	p1.print_board();
	p1.deploy();	
	
	f.open("player1.dat",ios::binary);
	f.write((char*) &p1, sizeof(p1));
	f.seekg(0);
	f.close();
	
	//f1.open("player1.dat"); <--- When these lines are used, the data is viewed correctly
	//f1.read((char*) &p2, sizeof(p2));
	//f1.close();
	
	//p2.print_board();
	
	getch();
}


and this is a separate code which reads from the file above saved...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//this is game.cpp
#include "main\main.cpp"
#include<fstream>

using namespace std;

int main()
{
	board p1, p2;
	fstream f;
	
	f.open("player1.dat");	
	//f.seekg(0);
	if(!f)
		cout<<"cant";
	f.read((char*) &p1, sizeof(p1));
	f.close();
	p1.print_board();
	
}


from player.cpp, the data is saved in player.dat and viewed correctly(in the same program)
But from game.cpp, when i retrive the data from player.dat, i get it incorrect

The class defination...

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
class board
{
	public:
		
		//int b[11][11];
		
		int ac;	//	Aircraft Carrier
		int bat;	//	Battleship
		int cur;	//	Cruiser
		int sub;	//	Submarine
		int des;	//	Destroyer

		//this array is the actual member to be changed in player.cpp, and meant to be saved in the player.dat
		char b[11][11]=
		{
				{' ','A','B','C','D','E','F','G','H','I','J'},
				{'0',0,0,0,0,0,0,0,0,0,0},
				{'1',0,0,0,0,0,0,0,0,0,0},
				{'2',0,0,0,0,0,0,0,0,0,0},
				{'3',0,0,0,0,0,0,0,0,0,0},
				{'4',0,0,0,0,0,0,0,0,0,0},
				{'5',0,0,0,0,0,0,0,0,0,0},
				{'6',0,0,0,0,0,0,0,0,0,0},
				{'7',0,0,0,0,0,0,0,0,0,0},
				{'8',0,0,0,0,0,0,0,0,0,0},
				{'9',0,0,0,0,0,0,0,0,0,0}
		};
		
		board()
		{
			ac=5;
			bat=4;
			cur=3;
			sub=3;
			des=2;
		}

.
.
.
.
and many more stuffs...
};


why do i get incorrect data while retrieving from game.cpp but, get the correct data while retrieving from player.cpp.
Plz someone help
Last edited on
The only thing I noticed so far is that when creating the output, the file is opened like this:
 
f.open("player1.dat",ios::binary);


But when opened for input, it is done like this:
 
f1.open("player1.dat")
or
 
f.open("player1.dat");


Notice the ios::binary has gone missing. It should be used throughout.

As far as the class board itself is concerned, it seems to contain only int and char types which should be safe to use like this.

If for example there was a std::string or some other non-fundamental type, that definitely would be a problem.

You don't have a minimal, compileable example, but if I edit some things, I got it to work by changing the first main() from.
f.open("player1.dat",ios::binary);
to
f.open("player1.dat",ios::binary|ios::out);

It prints

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
5
4
3
3
2
  A B C D E F G H I J
0
1
2
3
4
5
6
7
8
9

When I print out each row. Note that the 0's don't get printed by your standard console because they're null characters. If that's not the problem, it might be in code you're not showing?
My unsolicited opinion is:
#include "main.cpp"
1) you shouldn’t include a cpp file inside another cpp file (in general, cpp files shouldn’t be included, no matter where)

int main() int main()
2) There shouldn’t be more than one main() function in your entire program, no matter how many files it is comprised of.

char b[11][11]=
3) If your planning to realize a Battleship game, you’d better use a board of ints instead of chars, because it will make things easier.

4) You’d better adopt a better strategy for file naming, because you can’t know how many matches your’re going to play.
I’m attaching an example where the data file names are created from player names, i.e. a player named “Mary” will save her board in a “Mary.dat” file.
The following example is just a rough draft, but I hope it can be useful for hints.
To compile it you’ll need a command such as
g++ -std=gnu++17 -Wall -Wextra -pedantic-errors -pipe -O3 main.cpp Player.cpp -o main.exe
or similar.

main.cpp:
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
// NOTE: I changed the names not to interfere with you code, in case you want 
// to copy&paste some partes into yours.
#include <iostream>
#include "Player.h"

void waitForEnter();

// We are going to create two players with the same name for testing.
// In this code, two players shouldn't have the same name, otherwise they would
// share the same file for data.
int main()
{
    Player one;
    one.setName("JohnSmith"); // it's currently better to avoid spaces
    one.placeShips();
    one.saveBoardToFile();

    Player two;
    two.setName("JohnSmith");
    two.loadBoardFromFile();
    std::cout << '\n' << two.getName() << "'board is:\n" << two << '\n';
    waitForEnter();
    return 0;
}

void waitForEnter()
{
    std::cout << "\nPress ENTER to continue...\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}


BsBoard.h
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
59
60
61
62
63
64
65
66
67
68
69
#ifndef BSBOARD_H
#define BSBOARD_H

#include <fstream>
#include <iostream>
// Since this code is simplified, the following identifier must be in strict
// alphabetic order (ANSI table).
enum SHIPS_NAMES : char { AIRCRAFT    = 'A',
                          BATTLESHIP  = 'B',
                          CRUISER     = 'C',
                          DESTROYER   = 'D',
                          SUBMARINE   = 'E' };

class BsBoard {
public:
    int ac;     // Aircraft Carrier
    int bat;    // Battleship
    int cur;    // Cruiser
    int sub;    // Submarine
    int des;    // Destroyer

    // this array is the actual member to be changed in player.cpp, 
    // and meant to be saved in the player.dat
    char b[11][11] = {
                        {' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'},
                        {'0',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0},
                        {'1',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0},
                        {'2',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0},
                        {'3',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0},
                        {'4',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0},
                        {'5',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0},
                        {'6',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0},
                        {'7',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0},
                        {'8',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0},
                        {'9',  0,   0,   0,   0,   0,   0,   0,   0,   0,   0}
                     };
    BsBoard() : ac {5}, bat {4}, cur {3}, sub {3}, des {2}
        {}
    friend std::ofstream& operator<<(std::ofstream& of, const BsBoard& board)
    {
        for(int i{1}; i!=11; ++i) { // skip first row
            for(int j{1}; j!=11; ++j) { // skip first column
                of << board.b[i][j] << ' ';
            }
        }
        return of;
    }
    friend std::ifstream& operator>>(std::ifstream& inf, BsBoard& board)
    {
        for(int i{1}; i!=11; ++i) { // skip first row
            for(int j{1}; j!=11; ++j) { // skip first column
                inf >> board.b[i][j];
            }
        }
        return inf;
    }
    friend std::ostream& operator<<(std::ostream& os, const BsBoard& board)
    {
        for(int i{0}; i<11; ++i) {
            for(int j{0}; j<11; ++j) {
                os << board.b[i][j] << ' ';
            }
            os << '\n';
        }
        return os;
    }
};

#endif // BSBOARD_H 


Player.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef PLAYER_H
#define PLAYER_H

#include "BsBoard.h"

class Player {
    std::string name;
public:
    BsBoard myb;
    bool is_name_set;
    Player() : is_name_set {false} {}
    void setName(const std::string& newname);
    std::string getName() const;
    void saveBoardToFile() const;
    void loadBoardFromFile();
    void placeShips();
    friend std::ostream& operator<<(std::ostream& os, const Player& other)
    {
        return os << other.myb;
    }
};

#endif // PLAYER_H 

Player.cpp
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <string>
#include "Player.h"

void Player::setName(const std::string& newname)
{
    name = newname;
    is_name_set = true;
}

std::string Player::getName() const
{
    return name;
}

void Player::saveBoardToFile() const
{
    if(!is_name_set) {
        std::cout << "Can't know file name yet\n";
        return;
    }
    std::ofstream savefile(name + ".dat");
    savefile << myb;
    savefile.close();
}

void Player::loadBoardFromFile()
{
    if(!is_name_set) {
        std::cout << "Can't know file name yet\n";
        return;
    }
    std::ifstream loadfile(name + ".dat");
    loadfile >> myb;
    loadfile.close();
}

void Player::placeShips()
{
    std::cout << "\nIncomplete function.\nJust place one single ship to test "
                 "saving to and loading from file.\n"
                 "\nPlease give me a couple of integers from 0 to 9 to place "
                 "the ship.\nExample 3 5 will place a ship in position (3,F).\n"
                 "Position (0-9) (0-9)? ";
    int row {}, column {};
    // This do-while block just gets the position from the user
    do {
        std::string line;
        std::getline(std::cin, line);
        try {
            std::istringstream ss(line);
            int k {};
            ss >> k;
            if(k < 0 || 9 < k) { throw std::invalid_argument("1"); }
            else                { row = k + 1; }
            ss >> k;
            if(k < 0 || 9 < k) { throw std::invalid_argument("2"); }
            else                { column = k + 1; }
        } catch (std::invalid_argument& e) {
            if(e.what() == std::string("1")) {
                std::cout << "First position is not a number or is not in "
                             "range 1-10.\n\n";
            } else if(e.what() == std::string("2")) {
                std::cout << "First position is not a number or is not in "
                             "range 1-10.\n\n";
            }
            row = column = 0;
        } catch (std::out_of_range& e) {
            std::cout << "One of the typed numbers exceed storage capacity";
            row = column = 0;
        }
    } while(row < 1 || 10 < row || column < 1 || 10 < column);
    
    // This block just gets the ship type from the user
    int shiptype {};
    do {
        std::cout << "\nPlease indicate the ship type.\n"
                  << SHIPS_NAMES::AIRCRAFT   << " - Aircraft Carrier\n"
                  << SHIPS_NAMES::BATTLESHIP << " - Battleship\n"
                  << SHIPS_NAMES::CRUISER    << " - Cruiser\n"
                  << SHIPS_NAMES::DESTROYER  << " - Destroyer\n"
                  << SHIPS_NAMES::SUBMARINE  << " - Submarine\n"
                     "\n\nWhat type of ship (e.g. "
                  << SHIPS_NAMES::DESTROYER  << " for Destroyer)? ";
        std::string line;
        std::getline(std::cin, line);
        try {
            int k = std::stoi(line);
            SHIPS_NAMES ship = static_cast<SHIPS_NAMES>(k);
            if(ship < SHIPS_NAMES::AIRCRAFT || SHIPS_NAMES::SUBMARINE < ship) {
                throw std::invalid_argument("1");
            } else { 
                shiptype = k;
            }
        } catch (std::invalid_argument& e) {
            std::cout << "Unknown ship.\n\n";
        } catch (std::out_of_range& e) {
            std::cout << "The typed numbers exceed storage capacity";
        }
    } while(shiptype == 0);
    
    // Insert the ship inside the board
    myb.b[row][column] = static_cast<char>(shiptype);
}


Example output:
Incomplete function.
Just place one single ship to test saving to and loading from file.

Please give me a couple of integers from 0 to 9 to place the ship.
Example 3 5 will place a ship in position (3,5).
Position (0-9) (0-9)? 2 6

Please indicate the ship type.
65 - Aircraft Carrier
66 - Battleship
67 - Cruiser
68 - Destroyer
69 - Submarine


What type of ship (e.g. 68 for Destroyer)? 66

JohnSmith'board is:
  A B C D E F G H I J
0
1
2             B
3
4
5
6
7
8
9


Press ENTER to continue...

Topic archived. No new replies allowed.