将二进制文件中的数据读入C中的链接列表(访问冲突读取位置)

时间:2013-12-13 21:53:35

标签: c linked-list

编辑了代码,现在我从文件中读取时出现问题。我的结构没有得到值。

感觉我好像疯了,我正试图找到一个解决方案,比如8小时...所以这是我的结构

typedef struct _megye
{ 
    int megye;
    int hektar1_min;
    int hektar1_max;
    int hektar1_tam;
    int hektar2_min;
    int hektar2_max;
    int hektar2_tam;
    int hektar3_min;
    int hektar3_tam;
    struct _megye *next;
}megye;

嗯,它试图成为一个链表。以下是我尝试从我的文件中读取数据并将其放入结构中的方法:

{
    FILE *fb;
    megye*p;
    megye *mhead;
    mhead=(megye*)malloc(sizeof(megye));
    p=mhead;
    fb=fopen("tamogatas.dat", "rb");

    if (fread(p, 3, 7, fb) != 7)
    {
        printf("there was an error");
    }
    else
    {
        p=p->next;
        p=(megye*)malloc(sizeof(megye));
        p->next=NULL;
    }
    fclose(fb);
    return 0;
}

顺便说一句,我的文件是这样的:

  

1 50 100 2 100 200 4 200 6

这种7排。

所以如果我运行这个,那么我得到错误“访问违规读取位置”。请帮我做什么,在课堂上我们没有这样做,但他们仍然想要它。

3 个答案:

答案 0 :(得分:3)

这里似乎有几个问题。

一:

FILE *fb;
megye*p;
mhead=p=(megye*)malloc(sizeof(megye));

fb=fopen("tamogatas.dat", "rb");

if (fread(p, sizeof(megye), 7, fb) != 7)

我建议您避免使用a = b = c ...语法。它可能会导致细微的错误,并且在阅读时容易错过。然而,真正的问题是你期待在这里做什么。你的数据文件是二进制文件吗?如果没有,你将无法得到你所期望的。如果它是你希望它读取所有7个二进制结构值并将它们存储在仅为一个这样的结构分配的内存位置。这几乎肯定不是你想要做的。

{
    printf("there was an error");
}
else
{
    p=p->next=(megye*)malloc(sizeof(megye));
    p->next=NULL;
}
fclose(fb);
return 0;

在你的else子句中,你正在分配另一个结构位置并将p和p-> next设置为等于该位置。然后将p-> next设置为NULL。这几乎肯定不是你想要做的。

要形成链接列表,您需要一个指向NULL(空列表)或另一个节点的头。每个节点都有一个指向NULL(列表末尾)或列表中下一个节点的下一个字段。每个节点应单独分配,每个读取应只读取该节点(格式正确)。我猜你的输入文件是文本,所以你需要将每个数字转换为二进制值。一种方法是使用标准的fscanf(...)函数。

答案 1 :(得分:1)

我看到了代码中出现的两大类问题。

指针和列表

本条

    p=p->next;
    p=(megye*)malloc(sizeof(megye));
    p->next=NULL;

要么导致您的访问违规,要么会导致进一步的问题。

链表是一系列节点,其中每个节点都指向列表中的下一个节点。实现链接列表需要了解指针。我上面引用的三条线显示出对指针的深刻误解。

指针只是某些东西的地址。这里,p是某个节点的地址,p->next是该节点中包含NULL或列表中下一个节点地址的字段。

执行行p = p->next后,您忘记了上一个节点的地址,因此您无法再修改其next字段。对p的后续分配仅修改变量p本身,而不修改next之前值的p字段。

表示添加新节点以跟随p当前指向的节点的正确方法是:

    p->next = (megye*)malloc(sizeof(megye));
    p = p->next;
    p->next = NULL;

如果您想对错误检测迂腐,那么还要检查malloc()是否实际返回了非NULL值。您可以使用calloc()而不是malloc()来消除第三行,这也有利于将struct的所有字段初始化为全0位,这是C所要求的。 standard与数值0,0.0或NULL指针相同。

文件IO

您定义了struct megye显然是链表的节点结构(它包含一个next字段,该字段是指向该结构的指针),然后使用一个作为{{1的目标}}

fread()的调用将从文件中读取字节,并将它们放在您请求的缓冲区的内存中。它的参数是要填充的缓冲区的地址,数组元素的大小,元素的数量以及要从中读取的fread()

您写道:

FILE *

要求将7个字节结构的7个副本读入由 if (fread(p, 3, 7, fb) != 7) 指向的内存中,该内存之前已初始化为指向列表头节点的指针。您的列表节点大小不是3个字节。它有9个p字段和一个指针,在一个共同的32位架构上可能总共有40个字节。

结果,从文件中读取的21个字节(7个3字节元素)不会溢出分配。但是,它也没有与结构的任何部分对齐。

如果你真的有一个3字节整数的二进制文件,那么你需要引入一些读取文件并翻译格式的代码。

即使您打算保持自然大小的整数,将文件格式与内部表示分开也是一个好主意。一旦您尝试使用不同的架构系统交换此数据,您将看到好处。不同的机器可以具有int的不同值,即使大小相同,不同的平台也会以不同的顺序存储sizeof(int)的各个字节。

另一个问题是,由于您提到文件中有七行数据,因此您可能尝试在单个操作中读取整个列表。这不会像你期望的那样奏效。即使您在内存中有一个有效的链表,也不能简单地将其写入文件,因为指针将是在该特定运行的程序实例中有效的地址,并且无法写入文件并安全地读回。 / p>

有关这些文件I / O和数据表示问题的更多信息,请查看“序列化”这一广泛主题。这不是一个简单的问题。

出于学习目的,我强烈建议将序列化为简单的文本文件,以便您可以在文本编辑器中查看所获得的内容,并手动构建简单的测试用例。

答案 2 :(得分:0)

首先,在尝试阅读其内容之前,您可能需要注意fopen是否通过检查fb的值来成功打开文件。

然后,从我看到的,你只为你的1个节点(sizeof megye)分配了大小,但是你的fread调用,你试图在p地址设置7 * sizeof(megye)字节。

另一个问题是结构本身,因为您将数据和指针保存在列表的下一个节点中的结构相同,而不是从文件中填充。这意味着,您将从文件中为下一个设置任意地址。您的文件是否也包含下一个字段的字节?

我建议拆分你的结构。一个数据结构,另一个结构列表。然后,只填充结构的数据部分会更容易。

最后,如果这样可行,则无需强制转换malloc结果。隐式转换效果很好,可读性更高。

相关问题