从二进制文件读取后出现未处理的异常,当控制权返回给调用函数时
Unhandled exception after reading from a binary file, when control is returned to calling function
我是您论坛的新手,所以请原谅任何错误。我正在研究一个读取和写入二进制文件的 C++ 项目。我首先尝试在 c++ 上使用 full 来执行此操作,但是当出现错误时,我的导师告诉我使用 c 风格的文件操作。瞧,我得到了同样的错误:
CSI_FinalProj_EmployeeDB.exe 中 0x6087CCC8 (msvcp110d.dll) 的未处理异常:0xC0000005:读取位置 0x00CDDAEC 的访问冲突。
这发生在成功完成读取和打印并成功关闭文件之后。它总是在程序退出函数并尝试 return 调用函数时发生。如果我把它放在 main 中,它会在 return 之后爆炸,当程序结束时。
该函数是一个简单的打印函数:
void fileClerkType::printRecord(int id)const
{
FILE* spRead;
employeeType record;
long location;
long size;
location = id - 1;
size = sizeof(employeeType);
spRead = fopen("companyFile.dat", "r");
fseek(spRead, location*size, SEEK_SET);
fread(&record, sizeof(employeeType), 1, spRead);
// If a record has been deleted, the id will be 0
// In that case, don't print
if (record.getEmployeeID() != 0)
{
cout << record << endl;
fread(&record, sizeof(employeeType), 1, spRead);
}
fclose(spRead);
}//Unhandled exception at 0x5065CCC8 (msvcp110d.dll) in
//CSI_FinalProj_EmployeeDB.exe: 0xC0000005: Access violation
//reading location 0x00CDDAEC.
正如我所说,该功能完美运行。 employeeType 是一个 class 具有:
2 个整数、三个字符串和一个浮点数
这是有同样问题的原始c++版本。唯一的区别是这会打印所有记录。它也很完美。:
void administratorType::showAllRecords()
{
long test;
long position = 0;
long recordSize = sizeof(employeeType);
ifstream inFile("EmployeesNew.dat", ios::in | ios::binary);
employeeType buffer; // empty employeeType
if(inFile.is_open())
{
inFile.seekg((position * recordSize), ios::beg);
test = inFile.peek(); // Debug
inFile.read(reinterpret_cast<char*>(&buffer), recordSize);
position = 0;
while(position < getRecordCount())
{
inFile.seekg((position * recordSize), ios::beg);
test = inFile.peek();
inFile.read(reinterpret_cast<char*>(&buffer), recordSize);
outputRecord(cout, buffer);
position++;
}
inFile.close();
}
}// Runs fine to here, but throws error when leaving the function
// Unhandled exception at 0x5408CCC8 (msvcp110d.dll) in
// ProjectName.exe: 0xC0000005: Access violation
// reading location 0x0137D3B4.
这一定是一个实施问题。但我看不到它。实现中是否有什么东西导致跟踪函数调用和 returns 的指针被破坏?预先感谢您的帮助。
抱歉,这是 Employee class 的成员变量列表。它们不是固定长度的字符串:
int age;
int employeeID; // Auto-generated
float salary;
string lastName;
string firstName;
string ssn;
std::string
不是 trivially copyable 类型,因此没有 class 具有一个作为成员的类型也是可简单复制的。
您不能像这样按字节读取或写入非平凡可复制类型。由于大多数库采用 SSO(假设 lastName
、firstName
和 ssn
足够短),因此当您从字符串中读取时,该函数可能不会崩溃,但是您在销毁期间仍会 运行 遇到问题。
在 C++ 中序列化数据的规范方法是重载流运算符,这是一个示例:
std::istream& operator>>(std::istream& stream, employeeType& employee)
{
return stream >>
employee.age >>
employee.employeeID >>
employee.salary >>
employee.lastName >>
employee.firstName >>
employee.ssn;
}
std::ostream& operator<<(std::ostream& stream, employeeType const& employee)
{
return stream <<
employee.age << ' ' <<
employee.employeeID << ' ' <<
employee.salary << ' ' <<
employee.lastName << ' ' <<
employee.firstName << ' ' <<
employee.ssn << '\n';
}
可以在循环中读取或写入记录,例如
for (employeeType e; inFile >> e;)
//do something with e
或者您甚至可以使用
将它们复制到向量中
std::vector<employeeType> employees(
std::istream_iterator<employeeType>(inFile),
std::istream_iterator<employeeType>()
);
我创建了一个结构来保存正在读取到文件中的数据,然后将所有字符串转换为 char 数组。做这些都行不通,但结合起来却行。以下是带有 main() 和测试 class 的测试程序(带有结构。这就是我用来找到解决方案的方法。对于那些寻求 [=13 方法的人来说,这是一个工作程序=] 随机二进制文件(除非我在这里格式化时搞砸了)。
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
struct STUDENT
{
char lName[21];
int id;
float sal;
};
class Person
{
public:
struct STUDENT student;
string getlName() const
{
return student.lName;
}
int getID() const
{
return student.id;
}
float getSal() const
{
return student.sal;
}
// Insertion operator
friend std::ostream& operator<<(std::ostream& os, const Person& p)
{
// write out individual members of the struct with
// an end of line between each one
os << p.student.id << ' ' << p.student.lName
<< ' ' << p.student.sal << '\n';
return os;
}
// Extraction operator
friend std::istream& operator>>(std::istream& is, Person& p)
{
// read in individual members of struct
is >> p.student.id >> p.student.lName >> p.student.sal;
return is;
}
Person()
{
}
};
void outputLine( ostream&, const STUDENT&);
int main()
{
char lName[21] = {}; // Extra char for null
int id;
float sal;
int size = sizeof(STUDENT);
string more;
bool exit_now = false;
STUDENT buffer;
Person person;
// In order to randomly access data without destroying the file,
// you must use in and out (read/write mode).
fstream outFile("testFile.dat", ios::in | ios::out | ios::binary);
// Ensure file is opened
if(!outFile)
{
cerr << "Error: Out File could not be opened" << endl;
exit(1);
}
// ************* Random access inserting *************
do
{
cout << "Enter last Name\n?";
cin.getline(lName, 21);
int test;
test = strlen(lName); // FYI: this works to get char count
cout << "Enter salary\n?";
cin >> sal;
cout << "Enter ID\n?";
cin >> id;
strcpy_s(person.student.lName, lName); // copy input to struct
person.student.sal = sal;
person.student.id = id;
cout << person; // object being printed
outFile.seekp((person.student.id - 1) * size);
outFile.write(reinterpret_cast<const char* >(&person.student), size);
// Need this to get the next name
cin.clear();
cin.ignore();
cout << "Do you want to add another record? (yes or no)\n?"
<< endl;
cin >> more;
if (more == "no")
exit_now = true;
// Need this to get the next name properly
cin.clear();
cin.ignore();
}while(exit_now == false);
outFile.close();
// ************* Display Data *************
fstream inFile("testFile.dat", ios::in);
if(inFile) // Is there a connection
{
int target = 0;
int index = 0;
int position;
cout << "All records:" << endl;
while(inFile)
{
inFile.read(reinterpret_cast<char*>(&buffer), size);
if (buffer.id > 0)
{
target = inFile.tellg(); // Debug
cout << buffer.lName << endl;
}
//cout << buffer << endl; // This works
//cout << buffer.id << endl; // This works
}
cout << endl << "Search for a record by id" << endl << endl;
cout << "Enter an id: (0 to exit)" << endl;
cin >> target;
while(target > 0)
{
index = target - 1;
inFile.clear(); // Clear the flags. If the fail flags are
// are set, seekg() will not work.
// Position the file pointer
inFile.seekg(sizeof(Person)*index, ios::beg);
// Read information into the buffer (Person object)
// starting at the file pointer
inFile.read(reinterpret_cast<char*>(&buffer), size);
cout << buffer.lName << endl;
outputLine(cout, buffer);
cout << "Enter an id: (0 to exit)" << endl;
cin.clear();
cin >> target;
}
inFile.close();
cin.clear();
cin.get();
}else
cerr << endl << "Error: Could not complet the file connection."
<< "\nData could not be read."<< endl;
return 0;
}
void outputLine( ostream& output, const STUDENT& record)
{
//output << record << endl; // This works also
output << left << setw(20) << record.lName
<< setw(5) << record.id << setprecision(2)
<< right << fixed << showpoint
<< record.sal << endl;
}
我是您论坛的新手,所以请原谅任何错误。我正在研究一个读取和写入二进制文件的 C++ 项目。我首先尝试在 c++ 上使用 full 来执行此操作,但是当出现错误时,我的导师告诉我使用 c 风格的文件操作。瞧,我得到了同样的错误:
CSI_FinalProj_EmployeeDB.exe 中 0x6087CCC8 (msvcp110d.dll) 的未处理异常:0xC0000005:读取位置 0x00CDDAEC 的访问冲突。
这发生在成功完成读取和打印并成功关闭文件之后。它总是在程序退出函数并尝试 return 调用函数时发生。如果我把它放在 main 中,它会在 return 之后爆炸,当程序结束时。
该函数是一个简单的打印函数:
void fileClerkType::printRecord(int id)const
{
FILE* spRead;
employeeType record;
long location;
long size;
location = id - 1;
size = sizeof(employeeType);
spRead = fopen("companyFile.dat", "r");
fseek(spRead, location*size, SEEK_SET);
fread(&record, sizeof(employeeType), 1, spRead);
// If a record has been deleted, the id will be 0
// In that case, don't print
if (record.getEmployeeID() != 0)
{
cout << record << endl;
fread(&record, sizeof(employeeType), 1, spRead);
}
fclose(spRead);
}//Unhandled exception at 0x5065CCC8 (msvcp110d.dll) in
//CSI_FinalProj_EmployeeDB.exe: 0xC0000005: Access violation
//reading location 0x00CDDAEC.
正如我所说,该功能完美运行。 employeeType 是一个 class 具有:
2 个整数、三个字符串和一个浮点数
这是有同样问题的原始c++版本。唯一的区别是这会打印所有记录。它也很完美。:
void administratorType::showAllRecords()
{
long test;
long position = 0;
long recordSize = sizeof(employeeType);
ifstream inFile("EmployeesNew.dat", ios::in | ios::binary);
employeeType buffer; // empty employeeType
if(inFile.is_open())
{
inFile.seekg((position * recordSize), ios::beg);
test = inFile.peek(); // Debug
inFile.read(reinterpret_cast<char*>(&buffer), recordSize);
position = 0;
while(position < getRecordCount())
{
inFile.seekg((position * recordSize), ios::beg);
test = inFile.peek();
inFile.read(reinterpret_cast<char*>(&buffer), recordSize);
outputRecord(cout, buffer);
position++;
}
inFile.close();
}
}// Runs fine to here, but throws error when leaving the function
// Unhandled exception at 0x5408CCC8 (msvcp110d.dll) in
// ProjectName.exe: 0xC0000005: Access violation
// reading location 0x0137D3B4.
这一定是一个实施问题。但我看不到它。实现中是否有什么东西导致跟踪函数调用和 returns 的指针被破坏?预先感谢您的帮助。
抱歉,这是 Employee class 的成员变量列表。它们不是固定长度的字符串:
int age;
int employeeID; // Auto-generated
float salary;
string lastName;
string firstName;
string ssn;
std::string
不是 trivially copyable 类型,因此没有 class 具有一个作为成员的类型也是可简单复制的。
您不能像这样按字节读取或写入非平凡可复制类型。由于大多数库采用 SSO(假设 lastName
、firstName
和 ssn
足够短),因此当您从字符串中读取时,该函数可能不会崩溃,但是您在销毁期间仍会 运行 遇到问题。
在 C++ 中序列化数据的规范方法是重载流运算符,这是一个示例:
std::istream& operator>>(std::istream& stream, employeeType& employee)
{
return stream >>
employee.age >>
employee.employeeID >>
employee.salary >>
employee.lastName >>
employee.firstName >>
employee.ssn;
}
std::ostream& operator<<(std::ostream& stream, employeeType const& employee)
{
return stream <<
employee.age << ' ' <<
employee.employeeID << ' ' <<
employee.salary << ' ' <<
employee.lastName << ' ' <<
employee.firstName << ' ' <<
employee.ssn << '\n';
}
可以在循环中读取或写入记录,例如
for (employeeType e; inFile >> e;)
//do something with e
或者您甚至可以使用
将它们复制到向量中std::vector<employeeType> employees(
std::istream_iterator<employeeType>(inFile),
std::istream_iterator<employeeType>()
);
我创建了一个结构来保存正在读取到文件中的数据,然后将所有字符串转换为 char 数组。做这些都行不通,但结合起来却行。以下是带有 main() 和测试 class 的测试程序(带有结构。这就是我用来找到解决方案的方法。对于那些寻求 [=13 方法的人来说,这是一个工作程序=] 随机二进制文件(除非我在这里格式化时搞砸了)。
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
struct STUDENT
{
char lName[21];
int id;
float sal;
};
class Person
{
public:
struct STUDENT student;
string getlName() const
{
return student.lName;
}
int getID() const
{
return student.id;
}
float getSal() const
{
return student.sal;
}
// Insertion operator
friend std::ostream& operator<<(std::ostream& os, const Person& p)
{
// write out individual members of the struct with
// an end of line between each one
os << p.student.id << ' ' << p.student.lName
<< ' ' << p.student.sal << '\n';
return os;
}
// Extraction operator
friend std::istream& operator>>(std::istream& is, Person& p)
{
// read in individual members of struct
is >> p.student.id >> p.student.lName >> p.student.sal;
return is;
}
Person()
{
}
};
void outputLine( ostream&, const STUDENT&);
int main()
{
char lName[21] = {}; // Extra char for null
int id;
float sal;
int size = sizeof(STUDENT);
string more;
bool exit_now = false;
STUDENT buffer;
Person person;
// In order to randomly access data without destroying the file,
// you must use in and out (read/write mode).
fstream outFile("testFile.dat", ios::in | ios::out | ios::binary);
// Ensure file is opened
if(!outFile)
{
cerr << "Error: Out File could not be opened" << endl;
exit(1);
}
// ************* Random access inserting *************
do
{
cout << "Enter last Name\n?";
cin.getline(lName, 21);
int test;
test = strlen(lName); // FYI: this works to get char count
cout << "Enter salary\n?";
cin >> sal;
cout << "Enter ID\n?";
cin >> id;
strcpy_s(person.student.lName, lName); // copy input to struct
person.student.sal = sal;
person.student.id = id;
cout << person; // object being printed
outFile.seekp((person.student.id - 1) * size);
outFile.write(reinterpret_cast<const char* >(&person.student), size);
// Need this to get the next name
cin.clear();
cin.ignore();
cout << "Do you want to add another record? (yes or no)\n?"
<< endl;
cin >> more;
if (more == "no")
exit_now = true;
// Need this to get the next name properly
cin.clear();
cin.ignore();
}while(exit_now == false);
outFile.close();
// ************* Display Data *************
fstream inFile("testFile.dat", ios::in);
if(inFile) // Is there a connection
{
int target = 0;
int index = 0;
int position;
cout << "All records:" << endl;
while(inFile)
{
inFile.read(reinterpret_cast<char*>(&buffer), size);
if (buffer.id > 0)
{
target = inFile.tellg(); // Debug
cout << buffer.lName << endl;
}
//cout << buffer << endl; // This works
//cout << buffer.id << endl; // This works
}
cout << endl << "Search for a record by id" << endl << endl;
cout << "Enter an id: (0 to exit)" << endl;
cin >> target;
while(target > 0)
{
index = target - 1;
inFile.clear(); // Clear the flags. If the fail flags are
// are set, seekg() will not work.
// Position the file pointer
inFile.seekg(sizeof(Person)*index, ios::beg);
// Read information into the buffer (Person object)
// starting at the file pointer
inFile.read(reinterpret_cast<char*>(&buffer), size);
cout << buffer.lName << endl;
outputLine(cout, buffer);
cout << "Enter an id: (0 to exit)" << endl;
cin.clear();
cin >> target;
}
inFile.close();
cin.clear();
cin.get();
}else
cerr << endl << "Error: Could not complet the file connection."
<< "\nData could not be read."<< endl;
return 0;
}
void outputLine( ostream& output, const STUDENT& record)
{
//output << record << endl; // This works also
output << left << setw(20) << record.lName
<< setw(5) << record.id << setprecision(2)
<< right << fixed << showpoint
<< record.sal << endl;
}