You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

displayRecord函数执行后程序崩溃:读取访问违例问题求助

问题描述

displayRecord()函数能正常显示指定记录,但停顿一秒后程序在返回main()前意外崩溃,调试时触发错误:Exception thrown: read access violation. **_Val** was 0x19B6C345688。

已尝试在main()中打开文件并传入函数,也调用了clear()和seekg()重置文件位置,但问题依旧。

相关代码如下:

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

问题根源

直接对包含std::string的结构体进行二进制读写是错误操作。std::string内部存储的是指向堆内存的指针、字符串长度等元数据,而非实际的字符串内容。写入文件时保存的只是这些指针值;读出时,这些指针指向的内存已无效(要么是之前分配的内存已释放,要么是无关地址),访问此类内存就会触发读访问违规。

修复方案

有两种可行的修复方式:

方式一:使用固定长度字符数组替代std::string

将结构体中的std::string替换为固定大小的char数组,确保结构体内存布局固定,二进制读写安全。

修改后的结构体和displayRecord示例:

// 修改后的结构体
struct Item
{
    char description[50];  // 固定长度,可按需调整
    int quantity;
    double wCost;
    double rCost;
    char dateAdded[20];    // 固定长度,可按需调整
};

// 修改后的displayRecord(addRecord也需要对应修改写入逻辑)
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.close();

    return 0;
}

方式二:手动序列化/反序列化每个字段

不直接读写整个结构体,而是逐个读写每个字段。对于std::string,先写入/读出字符串长度,再写入/读出实际字符内容。

示例(仅展示displayRecord的读取逻辑,addRecord需对应写入逻辑):

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;

    // 跳过前面recNum-1个记录的内容,需与addRecord的写入格式严格对应
    // 读取description
    size_t descLen;
    inventoryFile.read(reinterpret_cast<char*>(&descLen), sizeof(descLen));
    item.description.resize(descLen);
    inventoryFile.read(&item.description[0], descLen);

    // 读取quantity
    inventoryFile.read(reinterpret_cast<char*>(&item.quantity), sizeof(item.quantity));

    // 读取wCost
    inventoryFile.read(reinterpret_cast<char*>(&item.wCost), sizeof(item.wCost));

    // 读取rCost
    inventoryFile.read(reinterpret_cast<char*>(&item.rCost), sizeof(item.rCost));

    // 读取dateAdded
    size_t dateLen;
    inventoryFile.read(reinterpret_cast<char*>(&dateLen), sizeof(dateLen));
    item.dateAdded.resize(dateLen);
    inventoryFile.read(&item.dateAdded[0], dateLen);
    
    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.close();

    return 0;
}

注意:方式二需要addRecord函数也按照相同的顺序和格式写入字段,否则会出现读取错位问题。

内容的提问来源于stack exchange,提问作者CodeBrewSlam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:58:10