【问题标题】:Segmentation fault when calling fread() c++调用 fread() c++ 时出现分段错误
【发布时间】:2015-01-03 13:57:49
【问题描述】:

我不明白我所犯的错误。 我尝试了很多,但我无法读取我的文件。 基本上,我根据帐户数量将结构写入名为 0.txt / 1.txt / 2.txt ... 的文件中。 我真的花了几个小时来解决我的问题,但我不明白我该如何解决以及为什么会出现错误。 我在编译我的代码(使用 dev c++)时也没有问题,但是当我按下加载帐户按钮时,我得到错误“Segmentation Fault”(使用 Windows 7)。 我注意到问题出在函数ladeAccounts() 中的fread() 行。 我的结构的名称是“iAccount”。 变量 infoma 是 iAccount 类型的,而 newAccount() 中的 int anzahl 类型的“现有帐户数”决定了路径。

iAccount 如下所示:

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

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

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 的结果。

【问题讨论】:

  • I realy seached hours to fix my problem 调用可以返回成功或失败的函数时,应检查返回值。你在没有检查返回值的情况下调用了fopen——不好。

标签: c++ segmentation-fault fread


【解决方案1】:

原因

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

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

说明

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

提示

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

附带问题

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

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

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

相反的操作更直接,因为您可以初始化一个 std::string 只需传递反序列化的字符数组:

std::string str(the_array);

【讨论】:

  • 谢谢,我会做一些测试,可能文件路径有问题。
  • @spyce14 很高兴为您提供帮助。作为旁注,还请阅读 Christophe 的回答:您的代码中还有其他问题,最值得注意的是您试图将非 POD strings 放入/读取文件。
【解决方案2】:

编辑 if(f2) 为真,所以我错了,文件已成功打开对吗?

我发现文件没有打开/fopen 无法处理例如 0.txt 的路径。 我也尝试直接输入路径而不构建它(没有字符串流等)。我仍然有分段错误的问题。我检查了文件夹 Accounts 中存在的所有文件。我在同一个文件夹中有另一个名为“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);    
}

我没问题!

【讨论】:

  • 是的,但现在您可能遇到了 _another_segmentation 错误。您是否设法调试并获得程序崩溃的行(例如使用 gdb)?
  • 我从来没有做过类似的事情,正如你所见,我在编程方面还很新。当我进入调试(如何)并找到线路时,我会回答。无论如何,我已经发现这不确定这意味着什么:线程 1 在第 5808667 行的 std::string::assign(char const*, unsigned int) 中停止,分段错误调试器关闭。
  • 问题是我在结构中的字符串。我可以将它们写入文件但不能读取它们。我在没有字符串的情况下尝试过,没有错误。
  • @AlexGidan 可能错误是我将结构中的两个字符串写入文件。当我想阅读它们时,fread 不知道这些字符串有多长,所以我决定使用 char 数组。你觉得我的想法怎么样?
  • 这是正确的方法。我用一些有用的提示更新了我的答案。
【解决方案3】:

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

它使用不那么琐碎的对象来提供灾难性的结果,特别是如果这些对象的内部管理动态内存分配和/或指针,就像这里的字符串一样。

顺便说一句:

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

编辑:

对不起,我读得不够好:如果它发生在fread(),那么provided by Alex 的原因肯定会有所帮助。但是我留下这个答案是因为一旦您解决了fopen() 问题,如果您尝试使用已阅读的对象,您可能会遇到分段错误。如果您不相信,请查看sizeof(iAccount) 并将其与您的字符串内容的大小进行比较。

【讨论】:

  • fread 发生的分段错误与此无关。 @spyce14 说 infoma 是一个结构实例,我看不出是如何产生分段错误的,因为 fread...
  • 我不知道这是否是导致崩溃的原因,但这确实是一个真正的问题。 std::string 实例不是数组。 fread 将摧毁他们。鼻恶魔无处不在。
  • 我同意你的看法,但这并不能回答问题,这是另一个问题。分段错误(或任何其他恶魔)将在以后发生......
  • @AlexGidan 你是完全正确的并且发现了正确的错误!不过,我认为这个答案也很有用。
猜你喜欢
  • 2022-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-17
  • 2017-08-05
  • 2015-10-03
  • 2018-05-15
  • 2019-04-20
相关资源
最近更新 更多