0

我创建了一个程序来使用 C++ 存储和检索链表,但不幸的是我的程序没有正确检索数据并返回代码 0xC0000005。我的程序有什么问题?我是初学者。

//C++ code
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <ctime>

using namespace std;

struct link
{
    link(int dat, link *nxt): data(dat), another(nxt)
    {
    }
    int data;
    link *another;
};

struct list
{
    link *first;
    ~list();
    list();
    void addnew();
    void displl();
}list;

list::list()
{
    fstream datafile;
    datafile.open("datafile", ios::in | ios::app);
    datafile.seekg(0, ios::end);
    int eb = datafile.tellg();
    if(!eb)
    {
        first = NULL;
        return;
    }
    datafile.seekg(0, ios::beg);
    link *head, *current, *preceding;
    head = preceding = current = NULL;
    while(eb)
    {
        if(!current)
        {
            datafile.read((char *)&current, sizeof(link));
            current->another = NULL;
            head = current;
        }
        preceding = current;
        datafile.read((char *)&current->another, sizeof(link));
        current = current->another;
        current->another = NULL;
        preceding->another = current;
        eb--;
    }
    first = head;
}

void list::addnew()
{
    srand(time(0) + rand());
    first = new link(rand()%10, first);
}

void list::displl()
{
    link *current;
    cout << endl << " - ";
    for(current = first; current; current = current->another)
        cout << current->data << " - ";
    cout << endl;
}

list::~list()
{
    fstream datafile;
    datafile.open("datafile", ios::out | ios::app);
    link *temp;
    while(first != NULL)
    {
        temp = first;
        first = first->another;
        datafile.write((char *)&temp, sizeof(link));
        delete temp;
    }
    first = NULL;
}

int main()
{
    list.addnew();
    list.addnew();
    list.addnew();
    list.displl();
    system("pause");
    return 0;
}
4

3 回答 3

1

我对初学者最喜欢的建议是从小而简单的开始,让它完美地工作,然后一点一点地增加复杂性,在每一步都进行测试。您在这里拥有三个独立的功能:基本列表、为列表分配随机值以及读取/写入列表。您应该独立开发这些,然后将它们组合起来;您不知道是哪个部分导致了问题的事实表明您试图一次将它们全部编写出来。(好吧,他们各自的代码纠缠在一起的事实也表明了这一点。)

最大的问题在于文件读取代码(在所有地方的默认构造函数中)。您正在将数据放入未初始化的内存中:

link *current;
...
current = NULL;
...
datafile.read((char *)&current, sizeof(link));

这就像在没有先找到杯子的情况下倒热咖啡一样。在尝试使用复杂类型之前,您应该使用简单类型(例如char,并且)进行读/写(并学会不要这样做) 。int然后尝试使用单个link. 然后和一堆。

于 2012-09-21T03:03:27.767 回答
0

正如 Beta 已经指出的那样,尝试读取链接时会发生访问冲突:

     ...
datafile.read((char *)&current, sizeof(link));
     ...

“current”是一个指针,在它上面使用“&”运算符会给出一个指向变量占用的内存的指针,它本身(在堆栈的某个地方)。所以代码尝试将一些链接大小的垃圾数据块读入这个指针——但这不会导致访问冲突。当“当前”被取消引用并用于写入它指向的“链接”对象的成员时会发生异常:

current->another = NULL;

它从数据文件加载的值来自同样不正确的序列化代码 - 没有保存任何“链接”数据。该文件包含的所有文件都是在堆上分配的“链接”对象的旧内存地址——这些地址是无效的,因为它们的内存是在先前的程序会话中分配的。

成功序列化对象的字节图像如下所示:

datafile.write(reinterpret_cast<const char*>(temp), sizeof(*temp));

但是“链接”对象不是普通的旧数据——在你销毁这个链接对象后,它包含的指针将无效。所以加载列表必须包括为每个链接分配内存(就像“addnew”一样)。

您可能只想遍历列表,从头部开始,并保存每个链接的有效负载数据,如下所示:

datafile.write(reinterpret_cast<const char*>(&temp->data), sizeof(temp->data));

然后,要加载列表,对于每个节点,将有效负载读入一个临时变量:

datafile.read(reinterpret_cast<char*>(&temp_data), sizeof(temp_data));

如果此操作成功,则分配并构造一个堆“链接”对象并将其连接到前一个节点:

next_tail = new link(temp_data, 0);
tail->another = next_tail;
tail = next_tail;
于 2012-09-21T04:36:03.523 回答
0

由于您在程序中进行指针操作,因此您会因为非法内存访问0xC0000005而出错。因为您没有提供完整的代码,所以您可能正在执行非法操作,例如未在程序的其他部分初始化指针。

于 2012-09-21T01:41:10.837 回答