0

我很迷茫。在将数据保存和加载到二进制文件时,我遇到了以下代码的问题。我有一段非常相似/精确的代码可用于不同的对象。我认为这与电子邮件地址和其中的 @ 符号有关。以下是重要的功能。

/* This is my save to file function */
FILE *file=fopen("patronsave","wb");
fwrite(&buffer,sizeof(buffer),1,file);
for(int i=0;i<3;i++){
Patron_Class *ppointer = new Patron_Class();
cout << "\n" << endl;
ppointer->save(file);
}
fclose(file);

这是我用来将对象保存到文件的功能。

这是我用来加载文件的代码:

vector<Patron_Class*> Patron_Entries;
FILE *file=fopen("patronsave","rb");
fread(&buffer,sizeof(buffer),1,file);
printf("Buffer: %d\n",buffer);
for(int i=0;i<buffer;i++){
    Patron_Class *pointer2 =new Patron_Class(file);
    Patron_Entries.push_back(pointer2);
    Patron_Entries[i] -> print();
    system("pause");
    }
fclose(file);

如果我运行保存功能,然后立即运行加载功能,它可以工作,但如果我只运行加载功能,它会在尝试加载电子邮件时崩溃。这是我的类和目标代码:

class Patron_Class{
public:
long patron_id;
string F_name;
string L_name;
long phone_num;
string email;
string street_address;
string city;
string state;
int zip_code;
Patron_Class(){
    cout << "Please enter a new ID" << endl;
    cin >> patron_id;
    cin.ignore(1000, '\n');
    system("cls");
    cout << "Please enter a First name" << endl;
    cin >> F_name;
    cin.ignore(1000, '\n');
    system("cls");
    cout << "Please enter a last name" << endl;
    cin >> L_name;
    cin.ignore(1000, '\n');
    system("cls");
    cout << "Please enter a phone number" << endl;
    cin >> phone_num;
    cin.ignore(1000, '\n');
    system("cls");
    cout << "Please enter a email" << endl;
    cin >> email;
    cin.ignore(1000, '\n');
    system("cls");
    cout << "Please enter a street address" << endl;
    cin >> street_address;
    cin.ignore(1000, '\n');
    system("cls");
    cout << "Please enter a city" << endl;
    cin >> city;
    cin.ignore(1000, '\n');
    system("cls");
    cout << "Please enter a State via it's initials" << endl;
    cin >> state;
    cin.ignore(1000, '\n');
    system("cls");
    cout << "Please enter a zip code" << endl;
    cin >> zip_code;
    cin.ignore(1000, '\n');
    system("cls");
    cout << "You have created a new patron named:   " << F_name << " " << L_name << endl;
}
Patron_Class(FILE *inputfile){
    fread(&patron_id, sizeof(patron_id),1,inputfile);
    fread(&F_name, sizeof(F_name),1,inputfile);
    fread(&L_name, sizeof(L_name),1,inputfile);
    fread(&phone_num, sizeof(phone_num),1,inputfile);
    fread(&email, sizeof(email),1,inputfile);
    fread(&street_address, sizeof(street_address),1,inputfile);
    fread(&city, sizeof(city),1,inputfile);
    fread(&state, sizeof(state),1,inputfile);
    fread(&zip_code, sizeof(zip_code),1,inputfile);
}

void print(){

    cout << patron_id << "    " << F_name << "    " << L_name << "    " << phone_num << "    " << email << "    " << street_address << "    " << city << "    " << state << "    " << zip_code << "\n" << endl;
}

void save(FILE *inputFile){
    fwrite(&patron_id, sizeof(patron_id),1,inputFile);
    fwrite(&F_name, sizeof(F_name),1,inputFile);
    fwrite(&L_name, sizeof(L_name),1,inputFile);
    fwrite(&phone_num, sizeof(phone_num),1,inputFile);
    fwrite(&email, sizeof(email),1,inputFile);
    fwrite(&street_address, sizeof(street_address),1,inputFile);
    fwrite(&city, sizeof(city),1,inputFile);
    fwrite(&state, sizeof(state),1,inputFile);
    fwrite(&zip_code, sizeof(zip_code),1,inputFile);
}


};

有谁知道它为什么会崩溃?

4

1 回答 1

1

这显然是错误的:

string F_name;

...
fread(&F_name, sizeof(F_name),1,inputfile);

...
fwrite(&F_name, sizeof(F_name),1,inputFile);

[这同样适用于你的所有其他字符串PatronClass- 我在这个例子中使用第一个]

这个类std::string看起来像这样(为了说明的目的,确切的实现涉及几个层、一些模板和其他东西,所以为了下面的解释,这被简化了):

class string
{
   char *str;
   int len;

 public: 
   ... 
 };

因此,当您fread从文件中执行并 fwrite 到文件时,您正在从/向文件读取/写入char *str;andint len;成员。

假设我们从头开始你的程序,文件中没有数据,我们使用Patron_Class()构造函数。所以我们读入一个 id,然后F_name从控制台读入。假设我们进入Charles. 所以不知何故,string该类将分配 8 字节的内存,地址为 0x600018。所以string::str == 0x600018-len = 8在堆中的位置 6000018 是字母C h a r l e s \0[ 空格只是为了说明它们位于不同的内存位置]。现在我们将它保存到一个文件中。所以文件包含00600018 00000008. PatronClass(file)现在我们使用构造函数停止程序并重新启动它。堆完全是空的。我们加载文件数据,所以string::str = 0x600018len = 8,但位置 0x600018 不包含C h a r l e s \0, 但无论堆初始化时通常使用的堆是什么[很可能是 0]。所以难怪你的名字没有出现。

现在,您的实际程序的确切行为可能与我上面描述的不同,但它不会正常工作。不可能,永远,永远。无论您的姓名、电子邮件地址或代码中的任何其他字符串中有或没有什么字符。它可能出现工作的唯一原因是数据在大多数情况下仍然存在于堆中,并且它似乎正在工作,因为在您的情况下它不会被其他东西覆盖。

于 2013-03-02T19:26:30.010 回答