tags:

views:

76

answers:

5
        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;


}

A: 

I'm not a C++ guru. Onething it doesn't seem correct here is that Object x in your code is not initialized.

kuriouscoder
I'm Calling the default constructor !. Do you have any other idea now to initialize it ?
Sudantha
Could you paste the entire code that shows this too?
kuriouscoder
+2  A: 

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.

TokenMacGuy
sorry, I didn't see your comment before posting mine
frag
thanks im getting the error now but how to overcome this ?
Sudantha
A: 

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);
}
};
frag
I Dont have any pointers in the class but have strings
Sudantha
strings like char* or like std:string?
frag
std:string are there can you please tell me to overcome this ? thanks !
Sudantha
I will try. First and most important: if you have strings, reading on from the file to the memory allocated for these objects will simply set them to random. One approach will be to add a method to Patient for saving and one for loading where the members of Patient will be saved (and loaded) one at a time. If the members are not simple in structure (i.e. not int, float, e.t.c.) you must provide methods to save the too. I suggest you post the structure of Patient
frag
Thanks a lot for your help here is the full class http://www.goo.gl/ChF6
Sudantha
ok, gimme a few minutes
frag
ok, I don't have a c++ compiler handy right now, so I only wish this compiles. Ok, I posted to code to the answer (I could not post it in a comment)
frag
thanks a lot ill go though this ! :D .. will i face any prob while reading the object from the file?
Sudantha
ahh, yes, I forgot... you should make the corresponding load... I'll post that too, just tell me if the save compiles
frag
ok, added load too. This method is very crude and saves and reads text. A binary form would use less space on the disk, but it gives you the idea I think
frag
thanks :D ill go though this ! :D
Sudantha
A: 

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;
}
PigBen
A: 

I figured it out using char arrays instead of strings will solve this problem , thanks all for your great help !

Sudantha