#include iostream
#include cmath
#include fstream
#include cstdlib
#include string
using namespace std;
class Device {//Input and store Device Description and Serial Numbers
protected:
string serial_number;
string device_description;
public:
Device() {
serial_number = ("6DCMQ32");
device_description = ("TheDell");
}
};
class Test {//Input and store Test Description, recent day, and month;
Calculate the next day
protected:
string Test_Description;
static int recent_month, recent_day, recent_year, new_month;
static int nmonth, next_month, next_day, next_year, max_day;
public:
Test() {
Test_Description = ("Virtual");
}
static void getMonth(ostream & out) {//Calculates the next/new month
next_month = recent_month + nmonth;
new_month = next_month % 12;
if (next_month >= 12) {
cout << "The next Date: " << new_month << " / ";
}
else {
out << "The next Date: " << next_month << " / ";
}
}
static void getDay(ostream & out) { //Calculates day of next month
if (new_month == 4 || new_month == 6 || new_month == 9 || new_month == 11) {
max_day = 30;
}
else if (new_month == 2) {
max_day = 29;
}
else {
max_day = 31;
}
if (recent_day > max_day) {
out << max_day << " / ";
}
else {
out << recent_day << " / ";
}
}
static void getYear(ostream & out) {// Calculate the year of next month
next_year = recent_year + next_month;
if (next_year >= 12) {
out << recent_year + (next_month / 12) << endl;
}
else {
out << next_year << endl;
}
}
static void getDate(ostream & out) {// Collects the output of each element of next date
getMonth(out), getDay(out), getYear(out);
}
};
int Test::recent_month;
int Test::recent_day;
int Test::recent_year;
int Test::new_month;
int Test::nmonth;
int Test::next_month;
int Test::next_day;
int Test::next_year;
int Test::max_day;
class Lab : public Device, public Test {
protected:
static int n;
public:
friend istream & operator>>(istream & in, Lab & lab) {// Inputs
cout << "Enter Device Desciption and Serial Number: ";
getline(cin, lab.device_description);
getline(cin, lab.serial_number);
cout << "Enter Test Desciption: ";
getline(cin, lab.Test_Description);
cout << "Enter the Number of months: ";
in >> nmonth;
cout << "Enter the Most Recent Date(mm/dd/yyyy): ";
in >> recent_month >> recent_day >> recent_year;
return in;
}
friend ostream & operator<<(ostream & out, Lab & lab) {//Outputs everything in Device Class
out << lab.device_description << endl;
out << lab.serial_number << endl;
out << lab.Test_Description << endl;
getDate(out);
return out;
}
static void getN() {
cout << "Enter the number of devices: ";
cin >> n;
}
static void getWrite() {
Lab *obj = new Lab[n];
if (obj == 0) {
cout << "Memory Error";
exit(1);
}
for (int i = 0; i<n; i++) {
cin >> obj[i];
cout << endl;
}
ofstream myfile("Device.dat", ios::binary);
myfile.write((char*) obj, n * sizeof(Lab));
delete[] obj;
}
static void getRead() {
ifstream file2("Device.dat", ios::binary);
Lab *obj2 = new Lab[n];
if (obj2 == 0) {
cout << "Memory Error";
exit(1);
}
file2.read((char*) obj2, n * sizeof(Lab));
for (int i = 0; i < n; i++) {
cout << obj2[i];
cout << endl;
}
delete[] obj2;
}
};
int Lab::n;
void main() {
Lab L;
L.getN();
L.getWrite();
L.getRead();
getchar();
getchar();
system("pause");
}
输出值后程序一直崩溃
目的:输入序列号输入设备下一次测试日期的月数, 设备描述、测试描述、最近日期和两次测试的月数。最后 必须通过让用户输入序列号和下一个日期来搜索程序,如果这两个是 列出设备中的所有内容。
我正在使用 Microsoft Visual Studios 2017
最佳答案
std::string
不幸的是,数据结构过于复杂,无法简单地写入文件。最简单的,一个 string
是指向字符数组的指针和存储数组长度的整数。当你写一个指向文件的指针时,你写的是地址,而不是地址上的数据。当您阅读 string
回到后者,很有可能你会得到一个指向程序不拥有的内存的陈旧地址和很多崩溃的坏处。更糟糕的是,如果回读地址指向程序中确实存在的内容。这些通常不会立即崩溃并使您远离实际的错误,因为破坏者正坐在另一段代码中,完全得意洋洋地吹口哨,因为您责备和调试错误的代码。无论哪种方式访问尚未分配给指针的内存都会调用 Undefined Behaviour ,而有了 UB,一切皆有可能。不要指望崩溃或一致性。
通常您会使用 operator <<
重载到 serialize the structure到文件而不是尝试二进制写入。如果您必须执行二进制写入,则需要创建一个协议(protocol)来描述必须如何写入和读取数据。
该协议(protocol)将是一组函数,可将更简单的数据类型与其等效文件进行相互转换。
编写 string
的典型方法就是先写string
的长度然后写入string
的内容.有点像
uint32 len = str.length(); //fixed width length
len = htonl(len); // fixed endian
myfile.write((char*) &len, sizeof(len)); //write length
myfile.write(str.data(), str.length()); //write string
阅读
uint32 len; //fixed width length
myfile.read((char*) &len, sizeof(len)); //read length
len = ntohl(len); // unfix endian
std::string str(len, ' '); //string and allocate size
myfile.write(str.data(), len); //read string C++17 or
//myfile.write(&str[0], len); //read string before C++17
将它们捆绑在函数中,您就可以开始使用您的协议(protocol)了。向它们添加您需要存储的其他数据类型的函数。
然后,这些函数会被转换更大数据类型的函数调用,直到您达到需要编写的最复杂的结构。对于数组,使用循环。如果你有一个可变大小的长度,就像使用 string
一样为长度添加前缀。 .
旁注:读取或写入数字时,必须小心确保数字是已知的固定大小。 int
,例如 , can be any size 16 bits or greater so long at it's not larger than
长. You don't necessarily know that the file reader will be using the same sized
int`,所以你应该更喜欢 Fixed Width Integer足够大以存储所需的值。不同的计算机也可能以不同的顺序存储它们的二进制信息。这叫做 Byte Order or Endian .确保每个人都使用相同的字节序。
关于c++ - 文件 I/O 二进制动态数组崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53384784/