程序在函数返回主函数之前关闭。抛出异常:读取访问冲突。 **_Val** 为 0x19B6C345688

问题描述 投票:0回答:1

我的

displayRecord()
功能运行正常。它将显示给定的记录,然后暂停一秒钟,但随后程序在函数返回到
main()
之前关闭。

调试后,我收到此错误:

抛出异常:读取访问冲突。
_Val 为 0x19B6C345688。

#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;

struct Item
{
    string description;
    int quantity;
    double wCost;
    double rCost;
    string dateAdded;
};

int addRecord();
int displayRecord();
int changeRecord();

int main()
{  
    cout << "Inventory Program" << endl;
    cout << "-------------------------------" << endl << endl;

    char again = 'y';
    int selection = 0;

    do 
    {
        cout << "MENU" << endl;
        cout << "----" << endl;
        cout << "1. Add a record" << endl;
        cout << "2. Display a record" << endl;
        cout << "3. Change a record" << endl;
        cout << "4. Exit Program" << endl << endl;

        do
        {
            cout << "Please enter a selection from the menu (1, 2, 3, or 4): ";
            cin >> selection;

            if (selection != 1 && selection != 2 && selection != 3 && selection != 4)
            {
                cout << "\nYou must enter a valid selection of either 1, 2, 3, or 4. Please try again.\n\n";
                
            }

        } while (selection != 1 && selection != 2 && selection != 3 && selection != 4);

        if (selection == 4)
        {
            cout << "Exiting Program..." << endl;
            cin.clear();
            return 0;
        }

        if (selection == 1)
        {   
            if (addRecord() == 1)
            {
                return 1;
            }
        }

        else if (selection == 2)
        {
            if (displayRecord() == 1)
            {
                return 1;
            }
        }

        else
        {
            if (changeRecord() == 1)
            {
                return 1;
            }
        }

        cout << "Return to menu? (Type Y for yes): ";
        cin >> again;

    } while (again == 'y' || again == 'Y');
    

    cout << "-------------------------------" << endl << endl;

    system("pause");

    return 0;

}

int displayRecord()
{
    fstream inventoryFile("inventory.dat", ios::in | ios::binary);
    if (!inventoryFile)
    {
        cout << "ERROR: Cannot open file. Aborting Program." << endl;
        return 1;
    }

    Item item;
    long recNum = 0;
    
    cout << "\nEnter the record number you wish to display: ";
    cin >> recNum;

    inventoryFile.seekg((recNum - 1) * sizeof(item), ios::beg);
    inventoryFile.read(reinterpret_cast<char*>(&item), sizeof(item));
    
    if (!inventoryFile)
    {
        cout << "\nERROR: Record does not exist." << endl << endl;
        inventoryFile.close();
        return 0;
    }

    else
    {
        cout << endl;
        cout << showpoint << setprecision(2) << fixed << endl;
        cout << "Item Description: " << item.description << endl;
        cout << "Quantity        : " << item.quantity << endl;
        cout << "Wholesale Cost  : " << item.wCost << endl;
        cout << "Retail Cost     : " << item.rCost << endl;
        cout << "Date Added:     : " << item.dateAdded << endl << endl;
        inventoryFile.clear();
    }
                  
    inventoryFile.close();

    return 0;
}

我有另一个分支,我在

main()
中打开文件并将文件传递给函数,但发生了同样的事情。

我使用

clear()
seekg()
设置文件开头的位置。

c++ exception access-violation
1个回答
0
投票

您的

Item
类型不平凡,因为它包含不平凡的
std::string
成员。因此,您不能使用
istream::read()
ostream::write()
以二进制模式读取/写入
Item
对象,就像您正在做的那样。

std::string
包含指向其字符数据的指针,该指针可能(通常)位于内存中的其他位置,位于
std::string
对象之外。您正在读取/写入
std::string
对象本身,而不是它们的字符数据。

要以二进制模式读取/写入项目,它们必须是简单类型。 为了促进代码使用的随机查找,这些项目需要具有固定大小。这意味着,您必须为字符串使用固定长度的

char[]
数组,例如:

struct Item
{
    char description[256];
    int quantity;
    double wCost;
    double rCost;
    char dateAdded[32];
};

否则,如果您想读/写

std::string
值,那么您必须(反)序列化*
Item
对象(这对随机查找不利),例如:

#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <cstdint>
#include <cstdio>
using namespace std;

struct Item
{
    string description;
    int quantity;
    double wCost;
    double rCost;
    string dateAdded;
};

template<typename T>
istream& read(istream &in, T &value)
{
    return in.read(reinterpret_cast<char*>(&value), sizeof(value));
}

template<typename T>
ostream& write(ostream &out, const T &value)
{
    return out.write(reinterpret_cast<const char*>(&value), sizeof(value));
}

istream& read(istream &in, string &value)
{
    uint32_t size;
    if (in.read(reinterpret_cast<char*>(&size), sizeof(size)))
    {
        value.resize(size);
        in.read(value.data(), size);
    }
    return in;
}

ostream& write(ostream &out, const string &value)
{
    uint32_t size = value.size();
    if (out.write(reinterpret_cast<char*>(&size), sizeof(size)))
        out.write(value.c_str(), size);
    return out;
}

istream& operator>>(istream &in, Item &item)
{
    read(in, item.description);
    read(in, item.quantity);
    read(in, item.wCost);
    read(in, item.rCost);
    read(in, item.dateAdded);
    return in;
}

ostream& operator<<(ostream &out, const Item &item)
{
    write(out, item.description);
    write(out, item.quantity);
    write(out, item.wCost);
    write(out, item.rCost);
    write(out, item.dateAdded);
    return out;
}

...

int addRecord()
{
    Item item;
    ...

    ofstream inventoryFile("inventory.dat", ios::binary | ios::app);
    if (!inventoryFile)
    {
        cout << "ERROR: Cannot open file. Aborting Program." << endl;
        return 1;
    }

    if (!(inventoryFile << item))
    {
        cout << "ERROR: Cannot write to file. Aborting Program." << endl;
        return 1;
    }

    return 0;
}

int displayRecord()
{
    ifstream inventoryFile("inventory.dat", ios::binary);
    if (!inventoryFile)
    {
        cout << "ERROR: Cannot open file. Aborting Program." << endl;
        return 1;
    }

    long recNum = 0;
    
    cout << "\nEnter the record number you wish to display: ";
    cin >> recNum;

    Item item;
    while (recNum > 1)
    {
        if (!(inventoryFile >> item))
        {
            cout << "\nERROR: Record does not exist." << endl << endl;
            return 0;
        }
        ---recNum;
    }
    
    if (!(inventoryFile >> item))
    {
        cout << "ERROR: Cannot read from file. Aborting Program." << endl;
        return 1;
    }

    cout << endl;
    cout << showpoint << setprecision(2) << fixed << endl;
    cout << "Item Description: " << item.description << endl;
    cout << "Quantity        : " << item.quantity << endl;
    cout << "Wholesale Cost  : " << item.wCost << endl;
    cout << "Retail Cost     : " << item.rCost << endl;
    cout << "Date Added:     : " << item.dateAdded << endl << endl;

    return 0;
}

int changeRecord()
{
    ifstream inventoryFile("inventory.dat", ios::binary);
    if (!inventoryFile)
    {
        cout << "ERROR: Cannot open file. Aborting Program." << endl;
        return 1;
    }

    ofstream inventoryTemp("inventory.tmp", ios::binary);
    if (!inventoryTemp)
    {
        cout << "ERROR: Cannot create file. Aborting Program." << endl;
        return 1;
    }

    long recNum = 0;
    
    cout << "\nEnter the record number you wish to change: ";
    cin >> recNum;

    Item item;
    while (recNum > 1)
    {
        if (!(inventoryFile >> item))
        {
            cout << "\nERROR: Record does not exist." << endl << endl;
            inventoryTemp.close();
            remove("inventory.tmp");
            return 0;
        }
        if (!(inventoryTemp << item))
        {
            cout << "ERROR: Cannot write to file. Aborting Program." << endl;
            inventoryTemp.close();
            remove("inventory.tmp");
            return 1;
        }
        ---recNum;
    }
    
    if (!(inventoryFile >> item))
    {
        cout << "ERROR: Cannot read from file. Aborting Program." << endl;
        inventoryTemp.close();
        remove("inventory.tmp");
        return 1;
    }

    // display item...
    // ask user for new values...

    if (!(inventoryTemp << item))
    {
        cout << "ERROR: Cannot write to file. Aborting Program." << endl;
        inventoryTemp.close();
        remove("inventory.tmp");
        return 1;
    };

    while (inventoryFile >> item)
    {
        if (!(inventoryTemp << item))
        {
            cout << "ERROR: Cannot write to file. Aborting Program." << endl;
            inventoryTemp.close();
            remove("inventory.tmp");
            return 1;
        }
    }

    if (!inventoryFile)
    {
        cout << "ERROR: Cannot read from file. Aborting Program." << endl;
        inventoryTemp.close();
        remove("inventory.tmp");
        return 1;
    }

    inventoryFile.close();
    inventoryTemp.close();

    remove("inventory.bak");
    rename("inventory.dat", "inventory.bak");
    rename("inventory.tmp", "inventory.dat");

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.