调用fread()c++时出现分段错误

Segmentation fault when calling fread() c++

本文关键字:分段 错误 c++ fread 调用      更新时间:2023-10-16

我不明白自己犯的错误。我试了很多次,但无法阅读我的文件。基本上,我会根据账户金额在一个名为0.txt/1.txt/2.txt的文件中写入一个结构。我确实花了几个小时来解决我的问题,但我不明白如何解决,也不明白为什么会出现错误。此外,我在编译代码(使用dev c++)时没有问题,但当我按下加载帐户按钮时,我会得到错误"分段错误t"(使用windows 7)。我注意到问题出现在函数ladeAccounts()中的fred()行。我的结构的名称是"iAccount"。变量infoma类型为iAccount,newAccount()中类型为int anzahl的"现有帐户数"决定路径。

iAccount如下所示:

 struct iAccount
    {
        string ID;
        string password;
        int level;
    };

这就是我将STRUCT写入文件的方式:

void Account::newAccount(int anzahl, string username, string pw, int lvl)
    {
        iAccount neu;
        neu.ID = username;
        neu.password = pw;
        neu.level = lvl; 
        ss.str("");
        ss<<anzahl;
        s = ss.str();
        s = "Accounts/"+s+".txt";        
        f1 = fopen(s.c_str(), "w");
        fseek(f1, 0, SEEK_SET);
        fwrite(&infoma, sizeof(iAccount), 1, f1);        
        fclose(f1);             
    }

这就是我读取文件的方式(调用fread()时出现错误

void Account::ladeAccount(int nummer)
    {
        stringstream sa;
        iAccount account_geladen;
        sa.str("");
        sa<<nummer;        
        s = sa.str();  
        s = "Accounts/"+s+".txt";     
        f2 = fopen(s.c_str(), "r"); 
        fseek(f2, 0, SEEK_SET);                  
        fread(&infoma, sizeof(infoma), 1, f2);               
        fclose(f2);                          
    }

谢谢你的帮助。我不知道我的问题在哪里,正如我所说,我正在寻找几个小时。

编辑:文件打开了,我试过了(f2是真的!)。

编辑":ERRNO=0!!!

参见此处:

ostringstream Str;
Str << errno;   
infoma.ID = Str.str(); 

这样做只是为了在我的wxtextlabel中查看errno的结果。

原因

您很可能是在NULL文件句柄上调用fread。所以这里有两个问题:

  1. 在代码中(不检查fread是否成功或返回NULL值)
  2. 由于某些原因无法打开您的文件(您应该调查…)

Explication

由于不同的原因,fopen(请参阅文档)可以返回NULL句柄。如果在调用fread之前不检查句柄的有效性,则会出现分段错误。

小贴士

正如您在我上面链接的官方文档中所读到的,在大多数库实现中,errno变量可以帮助您在失败时给出系统特定的错误代码。这可以帮助您调试打开文件时的错误。

次要问题

一旦你在我们的代码中解决了这个错误,你就会遇到其他问题。正如人们(尤其是@Christophe)在其他答案中所说,您的代码中存在结构问题,因为您试图对非POD文件对象(也称为字符串)进行序列化/反序列化。由于字符串是复杂的对象,所以不能直接序列化它们。

使用字符数组的方法将正确工作,因为简单的类型可以按照您的编码方式处理。

因此,可以使用std::stringc_str()方法从字符串中获取一个以null结尾的字符数组,并将其存储在文件中。

相反的操作甚至更简单,因为您可以初始化一个std::字符串,只需传递反序列化的字符数组:

std::string str(the_array);

您遇到了一个问题,因为您使用fread()加载二进制数据。但这只适用于普通的旧数据(POD)对象。

它用来用不那么琐碎的对象来提供不稳定的结果,尤其是当这些对象的内部管理动态内存分配器和/或指针时,就像这里的字符串一样。

顺便说一下:

如果您读/写二进制数据,您应该真正使用"rb"/"wb"作为fopen()的模式。如果你不这样做,你就不需要seg.fail,但你的数据在某些系统上可能不正确。

编辑:

对不起,我读得不够好:如果它发生在fread(),亚历克斯提供的理由肯定会有所帮助。然而,我留下这个答案是因为一旦你解决了fopen()问题,如果你试图处理你读到的对象,你可能会出现分割错误。如果您不满意,请查看sizeof(iAccount)并将其与字符串内容的大小进行比较。

编辑如果(f2)为真,那么我错了,文件被成功打开了,对吗?

我发现文件没有打开/fopen无法处理路径,例如0.txt。此外,我尝试在不构建路径的情况下直接进入路径(没有字符串流等)。我仍然有分割错误的问题。我检查了"帐户"文件夹中存在的所有文件。我在同一文件夹中有另一个名为"Accounts.txt"的文件,读取现有帐户的数量(也使用结构)没有问题。在那里,我甚至不检查fopen是否成功,但它仍然有效。我稍后会为文件打开检查编写代码。

读取/写入Accounts/Accounts.txt的代码为:

struct init{
    int anzahl_1;};
    init anzahl;
    FILE* f;
    static string ss = "Accounts/Accounts.txt";      
int account_anzahl1()
{ 
    f = fopen(ss.c_str(), "r");       
    fread(&anzahl, sizeof(init), 1, f); 
    fseek(f, 0, SEEK_END);      
    fclose(f);
    return anzahl.anzahl_1;

}
void account_anzahl_plus()
{
    anzahl.anzahl_1 = anzahl.anzahl_1 +1;     
    f = fopen(ss.c_str(), "w");
    fwrite(&anzahl, sizeof(init), 1, f);        
    fclose(f);    
}

我没有问题!