2

I'm working on c++ and I need to save this struct into a file:

struct myStruct{
    int value;
    int value2;
    MyClass * myClass[10];
};

The way that I'm saving this struct is the following:

myStruct my_struct;

my_struct.value = 1;
my_struct.value2 = 2;
for ( int i = 0; i < 10; i++){
    my_struct.myClass[i] = new MyClass();
} 

FILE* f = fopen(path.c_str(), "wb");

if ( f != NULL){

    fwrite(&my_struct, sizeof(myStruct), 1, f);
    fclose(f);
}

But, when I want to read this file, my program crashes when try to access to the array of "MyClass":

FILE* f = fopen(path.c_str(), "rb");

        if ( f != NULL){

            fread(&my_struct2, sizeof(struct myStruct), 1, f);
            fclose(f);
        }


        for ( int i = 0; i < 10; i ++ ){

            if ( my_struct2.myClass[i] != NULL ){

                //Here is the crash
            }
        }

I've been searching but I can't find a solution. I only find topics about arrays of structs. I know that maybe I'm not searching very well.

Thanks.

1
  • 2
    You are saving pointers to memory that you allocated in your process. If you load those in another process, they will be meaningless. To solve this, read up on the concept of serialization. Commented May 31, 2016 at 1:50

3 Answers 3

1

Your MyStruct contains twenty pointers to other structures.

By fwrite()ing the contents of your MyStruct to a file, you have successfully written twenty raw memory addresses of your other structures into the file, together with the other members of the MyStruct class.

Which, of course, is utterly meaningless when you try to read them back in another process. You've read back twenty raw memory addresses. Which mean nothing to a completely unrelated process. And, accessing those memory addresses, unsurprisingly, leads to a crash since those memory addresses, for all intents and purposes, are completely random values.

What your code needs to do is not write twenty raw pointer addresses to the file, but the contents of those pointers, and what they point to.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer @Sam. I'll see how I can do it. I do not have much experience with c ++ :(
1

I want to add some things to Sam's answer, even if I know this is not code review, you are writing C in C++.

C++ is not meant to be coded in C, it doesn't want to... It fought its entire life to break its bound with its deprecated father, to surpass him, to explore new meanings and way to solve problems and build efficient code. Don't do this to him... (I love C by the way, deprecated was a joke obviously ;) )

Here's how I'd do it:

#include <fstream>
#include <iostream>

class MyClass
{
public:
    MyClass() : _type(-1) {}
    MyClass(int type) : _type(type) {}

    inline const int    &type() const
    { return _type; }

private:
    int _type;
};

// -- overload of operator<< that permits me to write a MyClass* to a stream
std::ostream    &operator<<(std::ostream &stream, MyClass *myClass)
{
    stream << "myClass::type: " << myClass->type();
    return stream;
}

struct MyStruct
{
    int         value;
    int         value2;
    MyClass     *myClasses[10];

    MyStruct()
    {
        value = -1;
        value2 = 1;
        for (std::size_t i = 0 ; i < 10 ; ++i)
        { myClasses[i] = new MyClass(-i); }
    }
};

// -- overload of operator<< that permits me to write a MyStruct to a stream
std::ostream    &operator<<(std::ostream &stream, const MyStruct &myStruct)
{
    stream << "myStruct::"
            << "\n\t value: " << myStruct.value
            << "\n\t value2: " << myStruct.value2
            << "\n\t myClasses: ";
    for (std::size_t i = 0 ; i < 10 ; ++i)
    { stream << "\n\t\t " << myStruct.myClasses[i]; }
    return stream;
}

int main()
{
    std::ofstream outputFile("output.txt");

    if (outputFile.is_open() == false)
    { std::cerr << "Could not open file." << std::endl; return -1; }

    outputFile << MyStruct() << std::endl; // -- this is where the information is written into the file

    outputFile.close();
}

See simple way to write a struct, you could even get it back into the struct the same way with operator>> overload, bonus is you can use on any ostream, which means it will work with sstream, std::cout and everything!

Still this is not really c++-like as there is too much (unprotected) pointers and unchecked magical number sizes (MyClass *myClasses[10]; this is a no-no for me, because it implies this thing: for (std::size_t i = 0 ; i < 10 ; ++i), and this shit gives me shivers).

I would probably use an std::array here , but I wanted to keep MyStruct as you defined it so the example stay "close" to what you wrote. Another way would have been to use std::unique_ptr or std::shared_ptr.

This can seem as quite a bit of work or intimidating, but you may find that useful in the future. Same goes for using the std containers(array, set, vector, map, etc...), unique_ptr and shared_ptr. But I assure you it's worth giving some time to understand them and learn how to use them. It makes things simpler and safer.

What gave me shivers earlier would be written like this:

std::array<MyClass, 10> myClasses;

Loops would go like this:

for (std::size_t i = 0 ; i < myClasses.size() ; ++i)
{ myClasses[i].type(); }

for (std::array<MyClass, 10>::iterator itC = myClasses.begin() ; itC != myClasses.end() ; ++itC)
{ itC->type(); }

Or even better, a c++11 way to write a loop, that I find easier to read and write:

for (auto myClass : myClasses)
{ myClass.type(); }

Note that if you want to modify myClass inside this one you need to write auto& myClass : myClasses

Hope it helps you.

2 Comments

Thank you very much for your answer @vianney. It is more than clear that I have little experience with c ++. I put c code because it is what I have more present. I will work with the information you have provided.
Since you answered you had little experience with c++ in Sam's answer comment I thought some starting point could be helpful to you, and the little banter about C in C++ was a some kind of joke. Actually it can be really useful to have a good background in C to write C++ as you know better that pointers can put you in difficult situations and how.
0

Using fwrite(&my_struct, sizeof(myStruct), 1, f); is good if your struct my_struct contains purely static data(i.e the data for which memory was allocated at compile time). If it contains dynamic data(i.e the data for which memory is allocated at runtime) then you need to manually store such dynamic data. Overloading operator<< as shown my @vianney is a good method of saving/serializing dynamic data.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.