7 Replies - 1100 Views - Last Post: 06 February 2013 - 02:15 PM Rate Topic: -----

#1 Atrixium   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 9
  • Joined: 03-June 12

SegFault w/ Binary File I/O

Posted 06 February 2013 - 12:06 AM

I'm working on getting an understanding of Binary file I/O but have run into a stumbling block that I can't quite figure out.

Essentially what I have is a simple program that allows yoo to instantiate an object, add information to it, write that info to a file in either a sequential or binary format and then load it back into the program to be displayed.

The sequential portion works fine for saving, loading and displaying, it's just the binary portion where it's hurting my head.

What happens is this:

1st Run:
Run program,
instantiate object,
enter data,
display data,
save data to binary file,
display data,
load data from binary file,
display data,
quit


So far so good...

2nd Run:
Run program,
instantiate object,
load data from binary file,
display data,
SegFault


Boom, for some reason the program segfaults whenever I try to view the data that was loaded. Any pointers would be greatly appreciated!

The code is below:

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

//Globals
class PERSON
{
    public:
    PERSON() { cout << "\n\tBuilding a person..."; }
    ~PERSON() { cout << "\n\tDestroying a person..."; }

    void SetPersonName(string x) { PersonName = x; }
    void SetOccupation(string x) { Occupation = x; }
    void SetLocation(string x) { Location = x; }
    void SetReferences(string x) { References = x; }
    void SetAge(int x) { AGE = x; }
    void SetSize(float x) { SIZE = x; }
    void SetWeight(double x) { WEIGHT = x; }

    string GetPersonName() { return PersonName; }
    string GetOccupation() { return Occupation; }
    string GetLocation() { return Location; }
    string GetReferences() { return References; }
    int GetAge() { return AGE; }
    float GetSize() { return SIZE; }
    double GetWeight()  {return WEIGHT; }

    private:
    string PersonName;
    string Occupation;
    string Location;
    string References;
    int AGE;
    float SIZE;
    double WEIGHT;
};

//Protos----------------------------------------------------------
void CreatePerson();
void EditPerson();
void DisplayPerson();
void SavePerson();
void LoadPerson();
void SavePersonBinary();
void LoadPersonBinary();

PERSON * pPerson;
//-----------------------------------------------------------------

int main()
{
    char CHOICE[10];    //Could be single char but this is safer
 //   pPerson = new PERSON();

    cout << "\n\t Personnel Database \n";

    while(CHOICE[0] != 'q')
    {
        cout << "\n\t--------------------Main menu----------------";
        cout << "\n\t|                                           |";
        cout << "\n\t|              (C)reate a person            |";
        cout << "\n\t|              (E)dit a person              |";
        cout << "\n\t|              (D)isplay a person           |";
        cout << "\n\t|              (S)ave a person (Seq)        |";
        cout << "\n\t|              (L)oad a person (Seq)        |";
        cout << "\n\t|              (1)Save a person (Bin)       |";
        cout << "\n\t|              (0)Load a person (Bin)       |";
        cout << "\n\t|                                           |";
        cout << "\n\t---------------------------------------------\n\t";

        cin >> CHOICE;

        switch(CHOICE[0])
        {
            case 'c' : CreatePerson(); break;
            case 'e' : EditPerson(); break;
            case 'd' : DisplayPerson(); break;
            case 's' : SavePerson(); break;
            case 'l' : LoadPerson(); break;
            case '1' : SavePersonBinary(); break;
            case '0' : LoadPersonBinary(); break;
            case 'q' : cout << "\n\tExiting...\n\n"; break;
        }
    }

    return 0;
}
//-----------------------------------------------------------------
void CreatePerson()
{
    pPerson = new PERSON();
}
//-----------------------------------------------------------------
void EditPerson()
{
    string TEMP;
    char NumBuffer[10];

    cout << "\n\t-----------------------Edit Person-----------------";

    cout << "\n\tName: ";
    cin.ignore();
    getline(cin, TEMP);
    pPerson->SetPersonName(TEMP);

    cout << "\n\tAge: ";
    getline(cin, TEMP);
    for(int x = 0; x < TEMP.length(); x++)
        { NumBuffer[x] = TEMP[x]; }
    pPerson->SetAge(atoi(NumBuffer));

    cout << "\n\tSize: ";
    getline(cin, TEMP);
    for(int x = 0; x < TEMP.length(); x++)
        { NumBuffer[x] = TEMP[x]; }
    pPerson->SetSize(atof(NumBuffer));

    cout << "\n\tWeight: ";
    getline(cin, TEMP);
    for(int x = 0; x < TEMP.length(); x++)
        { NumBuffer[x] = TEMP[x]; }
    pPerson->SetWeight(atof(NumBuffer));

    cout << "\n\tOccupation: ";
    getline(cin, TEMP);
    pPerson->SetOccupation(TEMP);

    cout << "\n\tLocation: ";
    getline(cin, TEMP);
    pPerson->SetLocation(TEMP);

    cout << "\n\tReferences: ";
    getline(cin, TEMP);
    pPerson->SetReferences(TEMP);
}
//-----------------------------------------------------------------
void DisplayPerson()
{
    cout << "\n\t----------Person Information----------";
    cout << "\n\tName: " << pPerson->GetPersonName();
    cout << "\n\tAge: " << pPerson->GetAge();
    cout << "\n\tSize: " << pPerson->GetSize();
    cout << "\n\tWeight: " << pPerson->GetWeight();
    cout << "\n\tOccupation: " << pPerson->GetOccupation();
    cout << "\n\tLocation: " << pPerson->GetLocation();
    cout << "\n\tReferences: " << pPerson->GetReferences();
    cout << "\n\t--------------------------------------\n\n";

}
//-----------------------------------------------------------------
void SavePerson()
{
    try
    {
        ofstream DATAFILE;
        DATAFILE.open("data.bin",ios::out);

        DATAFILE << pPerson->GetPersonName() << endl;
        DATAFILE << pPerson->GetAge() << endl;
        DATAFILE << pPerson->GetSize() << endl;
        DATAFILE << pPerson->GetWeight() << endl;
        DATAFILE << pPerson->GetOccupation() << endl;
        DATAFILE << pPerson->GetLocation() << endl;
        DATAFILE << pPerson->GetReferences() << endl;

        DATAFILE.close();
        cout << "\n\tSuccess! Data was saved to file.";
    }
    catch(exception x)
    { cout << "\n\tI/O Error! Could not Save Person"; }
}
//-----------------------------------------------------------------
void LoadPerson()
{
    try
    {
        string temp;
        char NumBuffer[10];

        ifstream DATAFILE;
        DATAFILE.open("data.bin", ios::in);

        getline(DATAFILE, temp);
        pPerson->SetPersonName(temp);

        getline(DATAFILE, temp);
        for(int x = 0; x < temp.length(); x++)
            { NumBuffer[x] = temp[x]; }
        pPerson->SetAge(atoi(NumBuffer));

        getline(DATAFILE, temp);
        for(int x = 0; x < temp.length(); x++)
            { NumBuffer[x] = temp[x]; }
        pPerson->SetSize(atof(NumBuffer));

        getline(DATAFILE, temp);
        for(int x = 0; x < temp.length(); x++)
            { NumBuffer[x] = temp[x]; }
        pPerson->SetWeight(atof(NumBuffer));

        getline(DATAFILE, temp);
        pPerson->SetOccupation(temp);

        getline(DATAFILE, temp);
        pPerson->SetLocation(temp);

        getline(DATAFILE, temp);
        pPerson->SetReferences(temp);

        DATAFILE.close();

        cout << "\n\tSuccess! Data was loaded.";
    }
    catch(exception x)
    { cout << "\n\tI/O Error! Unable to load data!"; }
}
//-----------------------------------------------------------------
void SavePersonBinary()
{
    try
    {
        ofstream DATAFILE;
        DATAFILE.open("data.bin", ios::out | ios::binary);

        cout << "\n\tSize of a pPerson is: " << sizeof(*pPerson) << "\n";
        DATAFILE.write((char*) pPerson, sizeof(*pPerson));

        DATAFILE.close();

        cout << "\n\tOk! Data was saved successfully.";
    }
    catch(exception x) { cout << "\n\tError! Could not Save!"; }
}
void LoadPersonBinary()
{
    try
    {
        ifstream DATAFILE;
        DATAFILE.open("data.bin", ios::in | ios::binary);

        cout << "\n\tSize of a pPerson is: " << sizeof(*pPerson) << "\n";

        DATAFILE.read((char*) pPerson, sizeof(*pPerson));

        DATAFILE.close();

        cout << "\n\tSuccess! The data was loaded.";
    }
    catch(exception x)
        { cout << "\n\tError! Could not load data."; }
}


Is This A Good Question/Topic? 0
  • +

Replies To: SegFault w/ Binary File I/O

#2 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1467
  • View blog
  • Posts: 4,726
  • Joined: 20-March 10

Re: SegFault w/ Binary File I/O

Posted 06 February 2013 - 02:59 AM

Its the way your saving the class,

You cant just save the pointer and then load the pointer back into memory
the first time it works because there is actually something already there
at that memory location the second time there isnt and it seg faults for
overwriting memory.

What you are trying to do only works for POD types like char and int.

Snoopy.
Was This Post Helpful? 2
  • +
  • -

#3 Atrixium   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 9
  • Joined: 03-June 12

Re: SegFault w/ Binary File I/O

Posted 06 February 2013 - 08:38 AM

Hi Snoopy, thanks for the answer but I'm still a little unclear, I think I have a misunderstanding about what I think some of this code does vs what's actually happening.

If I understand correctly:

050	PERSON * pPerson;


creates a new pointer to a PERSON type object.


092	void CreatePerson()
093	{
094	    pPerson = new PERSON();
095	}


Instantiates a new object on the heap of PERSON type at the memory address pointed to by pPerson


221	void SavePersonBinary()
222	{
223	    try
224	    {
225	        ofstream DATAFILE;
226	        DATAFILE.open("data.bin", ios::out | ios::binary);
227	 
228	        cout << "\n\tSize of a pPerson is: " << sizeof(*pPerson) << "\n";
229	        DATAFILE.write((char*) pPerson, sizeof(*pPerson));
230	 
231	        DATAFILE.close();
232	 
233	        cout << "\n\tOk! Data was saved successfully.";
234	    }
235	    catch(exception x) { cout << "\n\tError! Could not Save!"; }
236	}


Opens a file in binary mode and then outputs a block of memory beginning with the pPerson pointer and extending out to the same number of bytes as the object that pPerson points to (since it's dereferenced).


The load function of course works in a similar manner where it opens the binary file and then reads in a chunk of data that is the size of the object pointed to by pPerson and then places it at the memory address pointed to by pPerson.

To my understanding that should allow the data to be read regardless of session, as the pPerson pointer created at the top will always point to a valid memory address since it was defined on the heap and shouldn't/can't run out of scope.

Obviously something is wrong in my understanding, but what is it?

Thanks!
Was This Post Helpful? 0
  • +
  • -

#4 Skydiver   User is online

  • Code herder
  • member icon

Reputation: 6287
  • View blog
  • Posts: 21,609
  • Joined: 05-May 12

Re: SegFault w/ Binary File I/O

Posted 06 February 2013 - 08:53 AM

You are forgetting that the string class internally has a pointer to its data. When you saved out your data to the file, you saved out the pointers to the strings (but not the string values). You are correct in allocation space for the Person class, and read the data in, but you also read in the old pointer values.

Basically consider this as the simplest case:
class Foo
{
    int * dynamicArray;
};



Saving an instance of Foo will only save the array pointer. When you reload Foo, you'll get back whatever the array pointer was. It will have no idea how much memory was allocated for the array or what values were in the array.

This post has been edited by Skydiver: 06 February 2013 - 08:54 AM

Was This Post Helpful? 1
  • +
  • -

#5 Atrixium   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 9
  • Joined: 03-June 12

Re: SegFault w/ Binary File I/O

Posted 06 February 2013 - 10:14 AM

That makes sense, however this line in the save/load function:

09	229         DATAFILE.write((char*) pPerson, sizeof(*pPerson));


Does this not take the pPerson pointer and then typecast it's object into a simple character array? Maybe I'm not thinking this through deeply enough, would this then typecast the address of the pointer into a char array and then encode that address in the binary file?

My confusion stems from this-> http://www.youtube.c...h?v=SHDUr-JlKK0

The code I have posted largely comes from this series of videos which I believe I have transcribed accurately. Originally I wrote a program based on the video to test my understanding and got this segfault. I assumed there was a fault in my code and so decided to transcribe the source directly (it wasn't posted) to see if I had indeed made an error in my understanding, but I get the same segfault while in the video the author is successful.

My question is then: How does this work for him and not for me? Have I made an error or is it an issue with my compiler/system?

In case it's relevant, I'm compiling with GCC.
Was This Post Helpful? 0
  • +
  • -

#6 Atrixium   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 9
  • Joined: 03-June 12

Re: SegFault w/ Binary File I/O

Posted 06 February 2013 - 10:39 AM

Sorry for the double post, can't find the edit button :/

Another thought: Maybe the author has made an error that is somehow making this possible?
Was This Post Helpful? 0
  • +
  • -

#7 Skydiver   User is online

  • Code herder
  • member icon

Reputation: 6287
  • View blog
  • Posts: 21,609
  • Joined: 05-May 12

Re: SegFault w/ Binary File I/O

Posted 06 February 2013 - 01:46 PM

The author on YouTube maybe using a version of the Standard Template Library that implements short string optimizations. Basically, the implementation of std::string has a small buffer built into it, so as long as the string is short, a pointer to dynamic memory is never used.
Was This Post Helpful? 1
  • +
  • -

#8 Atrixium   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 9
  • Joined: 03-June 12

Re: SegFault w/ Binary File I/O

Posted 06 February 2013 - 02:15 PM

Ahh yes, that makes sense! Now I can continue on, thanks for all your help!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1