#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
答案 0 :(得分:1)
std::string
的数据结构过于复杂,因此无法简单地写入文件。最简单的说,string
是指向字符数组的指针,是存储数组长度的整数。当您写一个指向文件的指针时,您写的是地址,而不是地址中的数据。当您阅读后面的string
时,很有可能出现一个陈旧的地址,该地址指向该程序不拥有的内存,并且崩溃很严重。更糟糕的是,如果回读地址指向程序中确实存在的内容。这些通常不会立即崩溃并导致您脱离实际的错误,因为当您责怪和调试错误的代码时,破坏者正坐在另一段完全自鸣得意的代码中。无论哪种方式,访问未分配给指针的内存都将调用Undefined Behaviour,对于UB,任何事情都可能发生。不要指望崩溃或一致性。
通常,您会使用operator <<
重载到文件serialize the structure,而不是尝试二进制写入。如果必须进行二进制写入,则需要创建一个协议来描述必须如何读写数据。
该协议将是一组将较简单的数据类型与其等价文件相互转换的函数。
写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
将这些捆绑在函数内部,就可以开始使用协议了。向其中添加用于您需要存储的其他数据类型的功能。
然后,这些函数将被用于转换较大数据类型的函数调用,直到达到最复杂的结构为止。对于数组,请使用循环。如果您有一个可变长度的长度,请像使用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。确保每个人都使用相同的字节序。