将带有指针数组的结构保存到文件中
Save struct with an array of pointers into a file
我正在使用 C++,我需要将这个结构保存到一个文件中:
struct myStruct{
int value;
int value2;
MyClass * myClass[10];
};
我保存这个结构的方式如下:
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);
}
但是,当我想读取这个文件时,我的程序在尝试访问 "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
}
}
我一直在寻找,但找不到解决方案。我只找到有关结构数组的主题。我知道可能我搜索的不是很好
谢谢。
您的 MyStruct
包含二十个指向其他结构的指针。
通过 fwrite
() 将 MyStruct
的内容写入文件,您已成功将其他结构的 20 个原始内存地址连同MyStruct
class.
当然,当您尝试在另一个进程中读回它们时,这毫无意义。您已经回读了 20 个原始内存地址。这对完全不相关的过程毫无意义。而且,毫无疑问,访问这些内存地址会导致崩溃,因为这些内存地址,就所有意图和目的而言,都是完全随机的值。
您的代码需要做的不是将 20 个原始指针地址写入文件,而是写入这些指针的内容以及它们指向的内容。
我想在 Sam 的回答中添加一些东西,即使我知道这不是代码审查,你正在用 C++ 编写 C。
C++ 并不意味着用 C 编写代码,它不想... 它一生都在努力打破与它已弃用的父亲的束缚,超越他,探索新的意义和解决问题的方法问题并构建高效的代码。不要这样对他...(顺便说一句,我喜欢 C,弃用显然是个笑话;))
这是我的做法:
#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();
}
查看编写结构的简单方法,您甚至可以使用运算符>>重载以相同的方式将其返回到结构中,好处是您可以在任何 ostream 上使用,这意味着它可以与 sstream 一起使用,std::cout 和一切!
这仍然不是真正的 c++-like,因为有太多(未受保护的)指针和未经检查的神奇数字大小(MyClass *myClasses[10];
这对我来说是一个禁忌,因为它暗示了这个东西:for (std::size_t i = 0 ; i < 10 ; ++i)
,这狗屎让我不寒而栗)。
我可能会在这里使用 std::array
,但我想保留您定义的 MyStruct,因此该示例保持 "close" 您所写的内容。另一种方法是使用 std::unique_ptr or std::shared_ptr.
这看起来工作量很大或令人生畏,但您将来可能会发现它很有用。使用 std 容器(数组、集合、向量、映射等)、unique_ptr 和 shared_ptr 也是如此。但我向您保证,花一些时间来理解它们并学习如何使用它们是值得的。它使事情变得更简单、更安全。
之前让我毛骨悚然的应该是这样写的:
std::array<MyClass, 10> myClasses;
循环会像这样:
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(); }
或者更好的是,一种编写循环的 c++11 方法,我发现它更易于读写:
for (auto myClass : myClasses)
{ myClass.type(); }
注意如果你想修改这个里面的myClass你需要写auto& myClass : myClasses
希望对你有帮助。
如果您的结构 my_struct
包含纯静态数据(即在编译时为其分配内存的数据),则使用 fwrite(&my_struct, sizeof(myStruct), 1, f);
很好。如果它包含动态数据(即在运行时为其分配内存的数据),那么您需要手动存储此类动态数据。
如我的@vianney 所示,重载 operator<<
是 saving/serializing 动态数据的好方法。
我正在使用 C++,我需要将这个结构保存到一个文件中:
struct myStruct{
int value;
int value2;
MyClass * myClass[10];
};
我保存这个结构的方式如下:
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);
}
但是,当我想读取这个文件时,我的程序在尝试访问 "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
}
}
我一直在寻找,但找不到解决方案。我只找到有关结构数组的主题。我知道可能我搜索的不是很好
谢谢。
您的 MyStruct
包含二十个指向其他结构的指针。
通过 fwrite
() 将 MyStruct
的内容写入文件,您已成功将其他结构的 20 个原始内存地址连同MyStruct
class.
当然,当您尝试在另一个进程中读回它们时,这毫无意义。您已经回读了 20 个原始内存地址。这对完全不相关的过程毫无意义。而且,毫无疑问,访问这些内存地址会导致崩溃,因为这些内存地址,就所有意图和目的而言,都是完全随机的值。
您的代码需要做的不是将 20 个原始指针地址写入文件,而是写入这些指针的内容以及它们指向的内容。
我想在 Sam 的回答中添加一些东西,即使我知道这不是代码审查,你正在用 C++ 编写 C。
C++ 并不意味着用 C 编写代码,它不想... 它一生都在努力打破与它已弃用的父亲的束缚,超越他,探索新的意义和解决问题的方法问题并构建高效的代码。不要这样对他...(顺便说一句,我喜欢 C,弃用显然是个笑话;))
这是我的做法:
#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();
}
查看编写结构的简单方法,您甚至可以使用运算符>>重载以相同的方式将其返回到结构中,好处是您可以在任何 ostream 上使用,这意味着它可以与 sstream 一起使用,std::cout 和一切!
这仍然不是真正的 c++-like,因为有太多(未受保护的)指针和未经检查的神奇数字大小(MyClass *myClasses[10];
这对我来说是一个禁忌,因为它暗示了这个东西:for (std::size_t i = 0 ; i < 10 ; ++i)
,这狗屎让我不寒而栗)。
我可能会在这里使用 std::array ,但我想保留您定义的 MyStruct,因此该示例保持 "close" 您所写的内容。另一种方法是使用 std::unique_ptr or std::shared_ptr.
这看起来工作量很大或令人生畏,但您将来可能会发现它很有用。使用 std 容器(数组、集合、向量、映射等)、unique_ptr 和 shared_ptr 也是如此。但我向您保证,花一些时间来理解它们并学习如何使用它们是值得的。它使事情变得更简单、更安全。
之前让我毛骨悚然的应该是这样写的:
std::array<MyClass, 10> myClasses;
循环会像这样:
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(); }
或者更好的是,一种编写循环的 c++11 方法,我发现它更易于读写:
for (auto myClass : myClasses)
{ myClass.type(); }
注意如果你想修改这个里面的myClass你需要写auto& myClass : myClasses
希望对你有帮助。
如果您的结构 my_struct
包含纯静态数据(即在编译时为其分配内存的数据),则使用 fwrite(&my_struct, sizeof(myStruct), 1, f);
很好。如果它包含动态数据(即在运行时为其分配内存的数据),那么您需要手动存储此类动态数据。
如我的@vianney 所示,重载 operator<<
是 saving/serializing 动态数据的好方法。