文件 I/O 二进制动态数组崩溃 [英] File I/O Binary Dynamic Array Crashed

查看:59
本文介绍了文件 I/O 二进制动态数组崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#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");
}

程序在输出值后一直崩溃

The program keeps on crashing after outputting the values

目的:是输入序列号输入设备下一次测试日期的月数,设备描述、测试描述、最近日期和两次测试的月数.最后必须通过让用户输入序列号和下一个日期来搜索程序,如果这两个是列出了设备中的所有内容.

Purpose: is to enter the number of months for the next test date of device with input of serial number, Device Description, Test Description, recent date, and the number of months of two tests. At the end the program must be searched by having the user to input the serial number and the next date, if these two are valid everything in the device is listed out.

我使用的是 Microsoft Visual Studios 2017

I am using Microsoft Visual Studios 2017

推荐答案

std::string 是一种过于复杂的数据结构,遗憾的是不能简单地写入文件.最简单的是,string 是一个指向字符数组的指针和一个存储数组长度的整数.当你写一个指向文件的指针时,你写的是地址,而不是地址处的数据.当你读回 string 后,很有可能你会得到一个陈旧的地址,指向程序不拥有的内存,并且有很多崩溃的坏处.更糟糕的是,如果回读地址指向程序中确实存在的某些内容.这些通常不会立即崩溃并使您远离实际错误,因为在您指责和调试错误代码时,破坏者正坐在另一段代码中,完全自鸣得意.无论哪种方式访问​​尚未分配给指针的内存都会调用 未定义行为,并且使用 UB 调用任何内容可以发生.不要指望崩溃或一致性.

std::string is far too complicated a data structure to simply write to a file unfortunately. At it's simplest, a string is a pointer to a character array and an integer storing the length of the array. When you write a pointer to a file, you write the address, not the data at the address. When you read the string back latter, odds are very good you wind up with a stale address pointing to memory that the program does not own and much crashing badness. Worse is if the read-back address points to something that does exist in the program. These generally don't crash right away and lead you away from the actual bug because the corruptor is sitting in another bit of code entirely whistling smugly as you blame and debug the wrong code. Either way accessing memory that has not been assigned to the pointer invokes Undefined Behaviour, and with UB anything can happen. Don't count on crashes or consistency.

通常,您会使用 operator << 重载来序列化结构到文件,而不是尝试二进制写入.如果必须进行二进制写入,则需要创建一个协议来描述必须如何写入和读取数据.

Generally you would use your operator << overloads to serialize the structure to the file rather than trying to binary write. If you have to do binary writes, you need to create a protocol that describes how data must be written and read.

该协议将是一组函数,用于在更简单的数据类型与其文件等效项之间进行转换.

The protocol is going to be a set of functions that convert simpler data types to and from their file equivalents.

string的典型方法是先写string的长度,然后写string的内容.类似的东西

A typical method for writing a string is to first write the length of the string and then write the contents of the string. Something like

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

将这些捆绑在函数内部,您就已经开始了您的协议​​.为您需要存储的其他数据类型添加函数.

bundle these up inside functions and you've started on your protocol. Add to them functions for other data types you need to store.

这些函数随后被转换较大数据类型的函数调用,直到您达到需要编写的最复杂的结构为止.对于数组,请使用循环.如果你有一个可变长度的长度,就像用 string 一样前缀长度.

These functions are then called by functions that convert larger datatypes and on up until you reach the most complex of the structures you need to write. For an array, use a loop. If you have a length of variable size, prefix the length just like with a string.

旁注:在读取或写入数字时必须注意确保数字是已知的、固定的大小.int,例如,可以是 16 位或更大的任意大小,只要不大于long.您不一定知道文件阅读器将使用相同大小的int`,因此您应该更喜欢 固定宽度整数 足够大以存储所需的值.不同的计算机也可能以不同的顺序存储它们的二进制信息.这称为字节顺序或字节序.确保每个人都使用相同的字节序.

Side note: When reading or writing numbers care must be taken to ensure the number is a known, fixed size. int, for example, can be any size 16 bits or greater so long at it's not larger thanlong. You don't necessarily know that the file reader will be using the same sizedint`, so you should prefer a Fixed Width Integer large enough to store the values required. Different computers also may store their binary information in different orders. This is called Byte Order or Endian. Make sure everyone is using the same endian.

这篇关于文件 I/O 二进制动态数组崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆