C++ creating an array in a temporary class - c++

Newbie question! I've started a small project that loads integer values from a file into an array. (The array needs to be accessed at random which is why i've chosen an array and not a vector.)
To load the data values from the file I've created a Load/Save class. The load function reads the first line of the file which gives us the total number of entries the array needs to have, then it will fill the array with the rest of the values in that file.
This load object is only created temporarily, I want to give the data to the program and then delete the object.
What is the best way to achieve this? should I create the array in main() and pass the load object a reference, in which case how can I create the array so it can be re-sized for the amount of data that needs loading..?
here is the load/save class:
class FileIOClass {
public:
FileIOClass();
int ReadFile(char*);
private:
};
this is the cpp code for the class:
FileIOClass::FileIOClass() {
}
int FileIOClass::ReadFile(char* file_name) {
string line;
ifstream file;
file.open(file_name, ios::in);
cout << "Loading data...\n";
int num_x, num_y, array_size;
bool machine_header = false;
if (file.is_open()) {
while(getline(file, line)) {
if (line.size() && machine_header == false) {
// Load machine header information
file >> num_x;
file >> num_y;
file >> array_size;
machine_header = true; // machine header has now been read, set this to true.
}
else {
// this is where i want to load the data from the file into an array.
// the size of the array should be equal to the value in array_size.
}
}
cout << "Loading complete!\n";
}
else {cout<<"File did not open!\n";}
file.close();
return 0;
}
and here is the main.cpp so far:
int main(int argc, char** argv)
{
FileIOClass data_in;
data_in.ReadFile(argv[1]);
return 0;
}
there will be several other classes that will process the data thats contained in the array.
I bet there are a load of odd newbie mistakes in this code - please feel free to point them out, better to learn these things now.
Thanks all!
Ian.

Somthing like this might be good:
vector<int> myVector(array_size);
for(int i=0; file && i<array_size; i++) {
file >> myVector[i];
}

As long as you've already decided on using a class to read the file, storing the data within the class seems reasonable. add a member to this class to store the data:
class FileIOClass {
public:
FileIOClass();
int ReadFile(char*);
unsigned int operator [](int i) const {return m_data[i];}
int size(void) { return m_data.size(); }
private:
std::vector<int> m_data;
};
and insert data into this member in your ReadFile method:
while(getline(file, line)) {
int pos = 0;
if (line.size() && machine_header == false) {
// Load machine header information
file >> num_x;
file >> num_y;
file >> array_size;
m_data.resize(array_size);
machine_header = true; // machine header has now been read, set this to true.
}
else {
file >> m_data[pos++];
// this is where i want to load the data from the file into an array.
// the size of the array should be equal to the value in array_size.
}
}
notice that I overloaded the [] operator, so you can use your class like this:
int main(int argc, char** argv)
{
FileIOClass data_in;
data_in.ReadFile(argv[1]);
if (data_in.size() >= 1)
cout << data_in[0];
return 0;
}

The array needs to be accessed at random which is why i've chosen an array and not a vector.
C++ vectors allow efficient random access (they are arrays under the hood). Use std::vector unless you have profiled your code and found them inefficient for what you are doing.

Related

C++ How to read data file to struct or vectors and return struct or vectors?

I already did this in MATLAB and want to do it in C++. The file I want to read from looks similar to:
0,397 0,372 0,385 0,354 0,397 0,384
0,389 0,347 0,385 0,317 0,397 0,380
0,379 0,308 0,381 0,285 0,395 0,361
Since the data is represented like that I had to choose a way to store it. I made a Class called OrlData which should have a function that read the text file and put the data into a array or a struct like:
struct DATA
{
float a[400];
string line;
} orldata[1200];
This struct should work like a normal array, orldata[1].a[2] = 0,347 and so on. But while searching for a better solution I figured that it was bad practice to return an array and it would be better to use vectors. (But I havent really had the breakthrough with those so I continued with structs)
My code is as below and is actually working. This is not implemented in the Class OrlData and is in the main until now. It is loading the file into the struct orldata:
struct DATA
{
float a[400];
string line;
} orldata[MAX];
int main()
{
int counter = 0;
int index = 0;
std::string Filename = "orl/orl_data.txt";
std::ifstream input(Filename);
std::string line;
while (std::getline(input, line)) {
counter++;
orldata[counter].line = line;
}
for (int i = 0; i < MAX; i++) {
std::istringstream iss(orldata[i].line);
for (std::string s; iss >> s; ) {
orldata[i].a[index] = strtof((s).c_str(), 0);
index++;
}
index = 0;
}
std::cout << orldata[2].a[5];
return 0;
}
But when I tried to put this code into a function which should return the struct it crashed:
DATA ORLData::create_orl_data() {
DATA orldata[1200];
....
return orldata[1200];
}
...
int main(){
ORLData orltemp;
ORLData::DATA orlstruct = orltemp.create_orl_data();
....
}
Until now I understood that it's bad practice to return struct arrays like this. And I learned that it's better to use vectors but I havent figured out how to actually use them as matrices.
So my problem can be summed to: I want to read from a text file that looks like the above and then load them into an array like array[0].a[2] which should store all the data. How can I do this?
Please ask if you want me to elaborate on the issues I have.
DATA ORLData::create_orl_data() {
DATA orldata[1200];
....
return orldata[1200];
}
is wrong on couple of accounts.
It can return only one element of the array.
The valid ranges for the index of orldata is 0-1199. return orldata[1200] accesses the array using an out of bounds index, and causes undefined behavior. In your case, that results in a crash.
Change that function to return a std::vector<DATA>.
std::vector<DATA> ORLData::create_orl_data() {
std::vector<DATA> orldata;
....
return orldata;
}

C++ Declaring arrays in class and declaring 2d arrays in class

I'm new with using classes and I encountered a problem while delcaring an array into a class. I want to initialize a char array for text limited to 50 characters and then replace the text with a function.
#ifndef MAP_H
#define MAP_H
#include "Sprite.h"
#include <SFML/Graphics.hpp>
#include <iostream>
class Map : public sprite
{
private:
char mapname[50];
int columnnumber;
int linenumber;
char casestatematricia[];
public:
void setmapname(char newmapname[50]);
void battlespace(int column, int line);
void setcasevalue(int col, int line, char value);
void printcasematricia();
};
#endif
By the way I could initialize my 2d array like that
char casestatematricia[][];
I want later to make this 2d array dynamic where I enter a column number and a line number like that
casestatematricia[linenumber][columnnumber]
to create a battlefield.
this is the cpp code so that you have an idea of what I want to do.
#include "Map.h"
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace sf;
void Map::setmapname(char newmapname[50])
{
this->mapname = newmapname;
}
void Map::battlespace(int column, int line)
{
}
void Map::setcasevalue(int col, int line, char value)
{
}
void Map::printcasematricia()
{
}
thank you in advance.
Consider following common practice on this one.
Most (e.g. numerical) libraries don't use 2D arrays inside classes.
They use dynamically allocated 1D arrays and overload the () or [] operator to access the right elements in a 2D-like fashion.
So on the outside you never can tell that you're actually dealing with consecutive storage, it looks like a 2D array.
In this way arrays are easier to resize, more efficient to store, transpose and reshape.
Just a proposition for your problem:
class Map : public sprite
{
private:
std::string mapname;
int columnnumber;
int linenumber;
std::vector<char> casestatematricia;
static constexpr std::size_t maxRow = 50;
static constexpr std::size_t maxCol = 50;
public:
Map():
casestatematricia(maxRow * maxCol, 0)
{}
void setmapname(std::string newmapname)
{
if (newmapname.size() > 50)
{
// Manage error if you really need no more 50 characters..
// Or just troncate when you serialize!
}
mapname = newmapname;
}
void battlespace(int col, int row);
void setcasevalue(int col, int row, char value)
{
// check that col and line are between 0 and max{Row|Column} - 1
casestatematricia[row * maxRow + col] = value;
}
void printcasematricia()
{
for (std::size_t row = 0; row < maxRow; ++row)
{
for (std::size_t col = 0; col < maxCol; ++col)
{
char currentCell = casestatematricia[row * maxRow + col];
}
}
}
};
For access to 1D array like a 2D array, take a look at Access a 1D array as a 2D array in C++.
When you think about serialization, I guess you want to save it to a file. Just a advice: don't store raw memory to a file just to "save" time when your relaunch your soft. You just have a non portable solution! And seriously, with power of your computer, you don't have to be worry about time to load from file!
I propose you to add 2 methods in your class to save Map into file
void dump(std::ostream &os)
{
os << mapname << "\n";
std::size_t currentRow = 0;
for(auto c: casestatematricia)
{
os << static_cast<int>(c) << " ";
++currentRow;
if (currentRow >= maxRow)
{
currentRow = 0;
os << "\n";
}
}
}
void load(std::istream &is)
{
std::string line;
std::getline(is, line);
mapname = line;
std::size_t current_cell = 0;
while(std::getline(is, line))
{
std::istringstream is(line);
while(!is.eof())
{
char c;
is >> c;
casestatematricia[current_cell] = c;
++current_cell;
}
}
}
This solution is only given for example. They doesn't manage error and I have choose to store it in ASCII in file. You can change to store in binary, but, don't use direct write of raw memory. You can take a look at C - serialization techniques (just have to translate to C++). But please, don't use memcpy or similar technique to serialize
I hope I get this right. You have two questions. You want know how to assign the value of char mapname[50]; via void setmapname(char newmapname[50]);. And you want to know how to create a dynamic size 2D array.
I hope you are comfortable with pointers because in both cases, you need it.
For the first question, I would like to first correct your understanding of void setmapname(char newmapname[50]);. C++ functions do not take in array. It take in the pointer to the array. So it is as good as writing void setmapname(char *newmapname);. For better understanding, go to Passing Arrays to Function in C++
With that, I am going to change the function to read in the length of the new map name. And to assign mapname, just use a loop to copy each of the char.
void setmapname(char *newmapname, int length) {
// ensure that the string passing in is not
// more that what mapname can hold.
length = length < 50 ? length : 50;
// loop each value and assign one by one.
for(int i = 0; i < length; ++i) {
mapname[i] = newmapname[i];
}
}
For the second question, you can use vector like what was proposed by Garf365 need to use but I prefer to just use pointer and I will use 1D array to represent 2d battlefield. (You can read the link Garf365 provide).
// Declare like this
char *casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char[column * line];
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
delete [] casestatematricia;
casestatematricia = 0;
}
Just remember to call clearspace() when you are no longer using it.
Just for your benefit, this is how you create a dynamic size 2D array
// Declare like this
char **casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char*[column];
for (int i = 0; i < column; ++i) {
casestatematricia[i] = new char[line];
}
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
for(int i = 0; i < columnnumber; ++i) {
delete [] casestatematricia[i];
}
delete [][] casestatematricia;
casestatematricia = 0;
}
Hope this help.
PS: If you need to serialize the string, you can to use pascal string format so that you can support string with variable length. e.g. "11hello world", or "3foo".

C++ Arrays and Vectors

I am new to C++ and this is not really part of my major so I am a little lost! If I can contact anyone personally for help please let me know :)
My program will need to read in ten integer values from a file, and store them in an array or vector. The reading of the values should be done in a separate function that takes an integer array as a parameter, and read from a file named tempInput.txt. I am unsure how to create an integer array as a parameter.
Then, from main, you will call another function, whose signature and return type is thus:
bool isDangerous(int tempArray[ ]);
If you could help me with part one or two that would be great!
namespace std;
int divison(int,int);
int main()
{
void readData(int tempArray[ ]);
int tempInput[10];
readData(tempInput);
//int size=10; //Array size
int sum =0;
//for(int i=0;i<size;i++) //Loop which inputs arrays data and
// {
//cout << myArray[i] << endl;
// }
return 0;
}
As best as I can understand the question, here's some code to get you started (Note that I haven't filled in everything exactly, I don't want to do your work for you)
#include<fstream> //So we can read from files
#include<iostream>
using namespace std;
void readData(int tempArray []) {
//Open file and read data into temp array
//If you need help reading data, see:
//http://www.cplusplus.com/doc/tutorial/files/
}
bool isDangerous(int tempArray []) {
//Do things
}
int main() {
int tempInput [10];
readData(tempInput); //Read the data into tempInput
bool result;
result = isDangerous(tempInput); //Do something with isDangerous
return 0;
}

Vector not clearing correctly

I'm having a problem clearing a vector of vectors.
I use a tuple function to return multiple variables.
I call to the tuple function twice in succession (using a different file each time).
When I check the outputs from the function, I get the equivalent of
vector1.size = vector1.size
and
vector2.size = (vector1.size + vector2.size)
rather than
vector1.size= vector1.size and vector2.size = vector2.size.
This leads me to believe that somewhere a vector is not being correctly cleared between the function calls, and that this is causing the second output to be written on top of the first output.
Below is my code:
main() and declarations
tuple<vector<float>, vector<vector<float>>, int> ReadFile(string fileToBeRead);
vector<float> sadInterpolationStorage;
vector<vector<float>> sadInterpolationVectorStorage;
vector<float> userInterpolationStorage;
vector<vector<float>> userInterpolationVectorStorage;
int sadAnimationLength;
int inputAnimationLength;
int main() {
tie(sadInterpolationStorage, sadInterpolationVectorStorage, sadAnimationLength) = ReadFile(sadWalkCycleMocapFile);
tie(userInterpolationStorage, userInterpolationVectorStorage, inputAnimationLength) = ReadFile(inputMocapFile);
cout << sadInterpolationVectorStorage[1].size() << endl;
cout << userInterpolationVectorStorage[1].size() << endl;
return 0;
}
userInterpolationVectorStorage[1].size() will always be equal to the sum of
(sadInterpolationVectorStorage[1].size()+ sadInterPolationVectorStorage[1].size(). It seems like a vector is not being cleared somewhere, but in ReadFile() I create new variables for everything.
ReadFile()
tuple<vector<float>, vector<vector<float>>, int> ReadFile(string fileToBeRead) {
string firstLineInFile;
string secondLineInFile;
string thirdLineInFile;
vector<float> interpolationStorage;
vector<vector<float>> interpolationVectorStorage;
int animationLength = 0;
vector<vector<float>> vectorStorage;
//Create a vector to hold all the mocap data values in float form.
vector<float> floatTokens;
//Create a vector to hold an entire frame (the data and the words).
vector<string> oneFrame;
//Create an input file stream
ifstream in(fileToBeRead, ios::in);
//cases to handle the first 3 lines of the file (first 3 lines contain no data, but are necessary)
//extracts each line into an object and writes them to the top of the output file
getline(in, firstLineInFile);
getline(in, secondLineInFile);
getline(in, thirdLineInFile);
//loop until the end of the file is reached
while (in.eof() == 0) {
//create a buffer to store each frame
stringstream buffer;
//write the frameID to the file.
extractFrameID(in);
//loop around the 29 lines in a frame, push each line into the vector.
for (int i = 0; i < 29; i++) {
string tempString;
getline(in, tempString);
//if the end of the file is reached (.empty() is used as the last line in the mocap file is always an empty line.
if (tempString.empty()) {
#pragma region Storing all data vectors in a vector
vectorStorage.push_back(rootXVector);
vectorStorage.push_back(rootZVector);
vectorStorage.push_back(lowerBackXVector);
vectorStorage.push_back(lowerBackYVector);
vectorStorage.push_back(lowerBackZVector);
vectorStorage.push_back(upperBackXVector);
vectorStorage.push_back(upperBackYVector);
vectorStorage.push_back(upperBackZVector);
vectorStorage.push_back(thoraxXVector);
vectorStorage.push_back(thoraxYVector);
vectorStorage.push_back(thoraxZVector);
vectorStorage.push_back(lowerNeckXVector);
vectorStorage.push_back(lowerNeckYVector);
vectorStorage.push_back(lowerNeckZVector);
vectorStorage.push_back(upperNeckXVector);
vectorStorage.push_back(upperNeckYVector);
vectorStorage.push_back(upperNeckZVector);
vectorStorage.push_back(headXVector);
vectorStorage.push_back(headYVector);
vectorStorage.push_back(headZVector);
vectorStorage.push_back(rClavicleYVector);
vectorStorage.push_back(rClavicleZVector);
vectorStorage.push_back(rHumerusXVector);
vectorStorage.push_back(rHumerusYVector);
vectorStorage.push_back(rHumerusZVector);
vectorStorage.push_back(rRadiusXVector);
vectorStorage.push_back(rWristYVector);
vectorStorage.push_back(rHandXVector);
vectorStorage.push_back(rHandYVector);
vectorStorage.push_back(rFingersXVector);
vectorStorage.push_back(rThumbXVector);
vectorStorage.push_back(rThumbZVector);
vectorStorage.push_back(lClavicleYVector);
vectorStorage.push_back(lClavicleZVector);
vectorStorage.push_back(lHumerusXVector);
vectorStorage.push_back(lHumerusYVector);
vectorStorage.push_back(lHumerusZVector);
vectorStorage.push_back(lRadiusXVector);
vectorStorage.push_back(lWristYVector);
vectorStorage.push_back(lHandXVector);
vectorStorage.push_back(lHandYVector);
vectorStorage.push_back(lFingersXVector);
vectorStorage.push_back(lThumbXVector);
vectorStorage.push_back(lThumbZVector);
vectorStorage.push_back(rFemurXVector);
vectorStorage.push_back(rFemurYVector);
vectorStorage.push_back(rFemurZVector);
vectorStorage.push_back(rTibiaXVector);
vectorStorage.push_back(rFootXVector);
vectorStorage.push_back(rFootZVector);
vectorStorage.push_back(rToesXVector);
vectorStorage.push_back(lFemurXVector);
vectorStorage.push_back(lFemurYVector);
vectorStorage.push_back(lFemurZVector);
vectorStorage.push_back(lTibiaXVector);
vectorStorage.push_back(lFootXVector);
vectorStorage.push_back(lFootZVector);
vectorStorage.push_back(lToesXVector);
#pragma endregion
//loop for every data type, 58 or so
for (size_t i = 0; i < vectorStorage.size(); i++) {
//interpolate between each data value and store the result in a vector.
//loop for every data value of every data type , 227 or so (1 per frame).
for (size_t j = 1; j < vectorStorage[i].size(); j++)
{
interpolationStorage.push_back(vectorStorage[i][j] - vectorStorage[i][j - 1]);
}
interpolationVectorStorage.push_back(interpolationStorage);
interpolationStorage.clear();
}
vectorStorage.clear();
cout << "Reading of " << fileToBeRead << " completed" << endl;
return make_tuple(interpolationStorage, interpolationVectorStorage, animationLength);
}
oneFrame.push_back(tempString);
}
//populate the buffer with the vector.
copy(oneFrame.begin(), oneFrame.end(), ostream_iterator<string>(buffer, "\n"));
//split the buffer up into tokens(objects) and store them into a vector
vector<string> mainTokenVector = split(buffer.str(), ' ');
//defining vectors.
vector<float> floatTokenVector;
vector<string> stringTokenVector;
//loop to split up the token vector into strings and floats, and store them in vectors
for (size_t i = 0; i < mainTokenVector.size(); i++) {
//if the token is a string, put it in the string vector
if (isFloat(mainTokenVector[i]) == 0) {
stringTokenVector.push_back(mainTokenVector[i]);
}
//if the token is a float, put it in the float vector
else if (isFloat(mainTokenVector[i]) == 1) {
floatTokenVector.push_back(stof(mainTokenVector[i]));
}
}
#pragma region Pushing data values to vectors
//pushing all data values to their responding vectors in order to interpolate between them later.
rootXVector.push_back(floatTokenVector[0]);
rootZVector.push_back(floatTokenVector[2]);
lowerBackXVector.push_back(floatTokenVector[6]);
lowerBackYVector.push_back(floatTokenVector[7]);
lowerBackZVector.push_back(floatTokenVector[8]);
upperBackXVector.push_back(floatTokenVector[9]);
upperBackYVector.push_back(floatTokenVector[10]);
upperBackZVector.push_back(floatTokenVector[11]);
thoraxXVector.push_back(floatTokenVector[12]);
thoraxYVector.push_back(floatTokenVector[13]);
thoraxZVector.push_back(floatTokenVector[14]);
lowerNeckXVector.push_back(floatTokenVector[15]);
lowerNeckYVector.push_back(floatTokenVector[16]);
lowerNeckZVector.push_back(floatTokenVector[17]);
upperNeckXVector.push_back(floatTokenVector[18]);
upperNeckYVector.push_back(floatTokenVector[19]);
upperNeckZVector.push_back(floatTokenVector[20]);
headXVector.push_back(floatTokenVector[21]);
headYVector.push_back(floatTokenVector[22]);
headZVector.push_back(floatTokenVector[23]);
rClavicleYVector.push_back(floatTokenVector[24]);
rClavicleZVector.push_back(floatTokenVector[25]);
rHumerusXVector.push_back(floatTokenVector[26]);
rHumerusYVector.push_back(floatTokenVector[27]);
rHumerusZVector.push_back(floatTokenVector[28]);
rRadiusXVector.push_back(floatTokenVector[29]);
rWristYVector.push_back(floatTokenVector[30]);
rHandXVector.push_back(floatTokenVector[31]);
rHandYVector.push_back(floatTokenVector[32]);
rFingersXVector.push_back(floatTokenVector[33]);
rThumbXVector.push_back(floatTokenVector[34]);
rThumbZVector.push_back(floatTokenVector[35]);
lClavicleYVector.push_back(floatTokenVector[36]);
lClavicleZVector.push_back(floatTokenVector[37]);
lHumerusXVector.push_back(floatTokenVector[38]);
lHumerusYVector.push_back(floatTokenVector[39]);
lHumerusZVector.push_back(floatTokenVector[40]);
lRadiusXVector.push_back(floatTokenVector[41]);
lWristYVector.push_back(floatTokenVector[42]);
lHandXVector.push_back(floatTokenVector[43]);
lHandYVector.push_back(floatTokenVector[44]);
lFingersXVector.push_back(floatTokenVector[45]);
lThumbXVector.push_back(floatTokenVector[46]);
lThumbZVector.push_back(floatTokenVector[47]);
rFemurXVector.push_back(floatTokenVector[48]);
rFemurYVector.push_back(floatTokenVector[49]);
rFemurZVector.push_back(floatTokenVector[50]);
rTibiaXVector.push_back(floatTokenVector[51]);
rFootXVector.push_back(floatTokenVector[52]);
rFootZVector.push_back(floatTokenVector[53]);
rToesXVector.push_back(floatTokenVector[54]);
lFemurXVector.push_back(floatTokenVector[55]);
lFemurYVector.push_back(floatTokenVector[56]);
lFemurZVector.push_back(floatTokenVector[57]);
lTibiaXVector.push_back(floatTokenVector[58]);
lFootXVector.push_back(floatTokenVector[59]);
lFootZVector.push_back(floatTokenVector[60]);
lToesXVector.push_back(floatTokenVector[61]);
#pragma endregion
//clear the vectors to prepare them for the next frame.
oneFrame.clear();
mainTokenVector.clear();
stringTokenVector.clear();
floatTokenVector.clear();
animationLength++;
}
//close the file currently associated with the object, disassociating it from the stream.
in.close();
}
I've spent the past few hours trying to figure out why this is happening, with no success, so any help at all would be greatly appreciated. If you have any queries let me know.
Cheers!
Figured it out.
I had declared all the body vectors( lowerBackXVector
lowerBackYVector
lowerBackZVector) etc outside the function, therefore they were not getting reset. I defined them within the function and now it works perfectly. Thanks guys.

C++ Reading Objects from File Error

fstream file;
Patient Obj("XXX",'M',"XXX");
file.open("Patients.dat",ios::in|ios::out|ios::app);
file.seekg(ios::end);
file.write((char*)&Obj,sizeof(Obj));
file.seekg(ios::beg);
Patient x;
file.read((char*)&x,sizeof(x));
x.printallInfo();
file.close();
I'm writing objects to files using this code but when i reading data VC++ 6 Crashes and thows a exception 'Access violation' .(Writing is successful)
Entire Code
#include <iostream>
#include<fstream>
#include <iomanip.h>
#include "Patient.cpp"
using namespace std;
int main(){
fstream file;
Patient Obj("XXX",'M',"XXX");
file.open("Patients.dat",ios::in|ios::out|ios::app);
file.seekg(ios::end);
file.write((char*)&Obj,sizeof(Obj));
file.seekg(ios::beg);
Patient x;
file.read((char*)&x,sizeof(x));
file.close();
return 0;
}
That seems like a brittle and non-portable way to marshal classes. One thing that could be happening with the way you do this is that you aren't making a deep copy of the data you're serializing. for instance, if one of the members of your Patient class is a std::string, a bare pointer is written to the file, but no string data is written. Worse, when you read that back in, the pointer points... somewhere...
A better way to deal with this issue is to actually implement a class specific method that knows exactly how to serialize and unserialize each member.
I'm not a C++ guru. Onething it doesn't seem correct here is that Object x in your code is not initialized.
Here's how you can read and write strings:
void writestring(std::ostream & out, const std::string & s)
{
std::size_t size = s.size();
out.write((char*)&size,sizeof(size));
out << s;
}
std::string readstring(std::istream & in)
{
std::size_t size;
in.read((char*)&size,sizeof(size));
char* buf = new char[size+1];
in.read(buf,size);
buf[size] = 0;
std::string s(buf);
delete [] buf;
return s;
}
If patient has pointers (e.g. to strings as I think it does based on its constructor) then your saving saves just the pointers, not values they point to. So loading initializes pointers to places in memory which might well be deleted or moved.
ok, here is the code I could not add to the comment below
class Patient : public Person{
.....
bool savePerson(fstream& stream) const
{
// you should do to Person the same thing I did for Patient
return true;
}
bool saveMedicalDetails(fstream& stream) const
{
for(int i=0;i<5;i++)
{
stream<<mD[i].number<<endl;
// we suppose here that the strings cannot contain 'end-of-line'
// otherwise you should save before any data of a string
// the number of characters in that string, like
// stream<<mD[i].doctors_name.size()<<" "<<mD[i].doctors_name<<endl;
stream<<mD[i].doctors_name<<endl;
stream<<mD[i].diognosis<<endl;
stream<<mD[i].medicine<<endl;
stream<<mD[i].date<<endl;
}
return stream;
}
bool savePaymentDetails(fstream& stream)const
{
stream<<pD.admisson<<endl;
stream<<pD.hospital_charges<<endl;
stream<<pD.doctor_charges<<endl;
return stream;
}
bool save(fstream& stream) const
{
return savePerson(stream) ||
saveMedicalDetails(stream) ||
savePaymentDetails(stream);
}
bool loadPerson(fstream& stream)
{
// you should do to Person the same thing I did for Patient
return true;
}
bool loadMedicalDetails(fstream& stream)
{
for(int i=0;i<5;i++)
{
stream>>mD[i].number;
// we suppose here that the strings cannot contain 'end-of-line'
// otherwise you should load before any data of a string
// the number of characters in that string, like
// int size;
// stream>>size;
// char *buffer=new char[size+1];
// stream.read(buffer,size);
// *(buffer+size)=0;
// mD[i].doctors=buffer;
// delete [] buffer;
getline(stream,mD[i].doctors);
getline(stream,mD[i].diognosis);
getline(stream,mD[i].medicine);
getline(stream,mD[i].date);
}
return stream;
}
bool loadPaymentDetails(fstream& stream)
{
stream>>pD.admisson;
stream>>pD.hospital_charges;
stream>>pD.doctor_charges;
return stream;
}
bool load(fstream& stream) const
{
return savePerson(stream) ||
saveMedicalDetails(stream) ||
savePaymentDetails(stream);
}
};
I figured it out using char arrays instead of strings will solve this problem , thanks all for your great help !