【问题标题】:Segmentation fault in File I/O文件 I/O 中的分段错误
【发布时间】:2011-06-03 21:25:45
【问题描述】:

我编写了一个代码来读取文件,将其存储在结构中并显示它。但不知何故,它给了我一个分段错误,我不知道为什么。有人可以帮帮我吗?

输出:

file: /home/neel/map2.txt
file opened
Start Intersection
a->road: 4

a->roadId[0]: 1
a->lane[0][0]: 2
a->lane[0][1]: 2

a->roadId[1]: 2
a->lane[1][0]: 2
a->lane[1][1]: 2

a->roadId[2]: 3
Segmentation fault

代码:

#include <iostream>
#include <fstream>
#include <stdio.h>
using namespace std;

struct Intersection
{
  unsigned short road;
  long long int *roadId;
  short *lane[2];
};

int main(int argc, char** argv)
{
  std::ifstream file;
  cout<<"file: "<<argv[1]<<endl;
  file.open(argv[1], std::ios::in);
  cout<<"file opened"<<endl;

  while (!file.eof())
  {
    cout<<"Start Intersection"<<endl;
    Intersection *a = new Intersection;
    file>>a->road;
    a->roadId = new long long int[a->road];
    a->lane[0] = new short[a->road];
    a->lane[1] = new short[a->road];
    cout<<"a->road: "<<a->road<<endl;
    for (int i=0; i<a->road; i++)
    {
      file>>a->roadId[i];

      cout<<endl<<"a->roadId["<<i<<"]: "<<a->roadId[i]<<endl;
      file>>a->lane[i][0];
      cout<<"a->lane["<<i<<"][0]: "<<a->lane[i][0]<<endl;
      file>>a->lane[i][1];
      cout<<"a->lane["<<i<<"][1]: "<<a->lane[i][1]<<endl;
    }
    cout<<"Intersection inserted"<<endl;
    delete a;
  }
}

文本文件:

4

1
2
2

2
2
2

3
2
2

4
2
2

【问题讨论】:

  • 文件>>a->lane[i][0];这看起来不对。 a->lane 是一个二维数组,其中第一个索引是 0 或 1,第二个索引是从 0-># of road (-1)

标签: c++ pointers file-io segmentation-fault fstream


【解决方案1】:

您的 lane 是一个包含 2 个元素的数组,但是当 i 在您的内部循环中到达 2 时,您正在尝试打印不存在的 a-&gt;lane[2][0]

【讨论】:

  • 啊,我明白了。我犯了一个愚蠢的错误。它应该是 file>>lane[0][i] 而不是 file>>lane[i][0].. 感谢您的帮助。
【解决方案2】:
file>>a->lane[i][0];  //wrong
file>>a->lane[i][1];  //wrong

索引应该是相反的:

file>>(a->lane[0][i]); //correct
file>>(a->lane[1][i]); //correct

为了清楚起见,我添加了括号。

此外,您的程序中存在内存泄漏。 delete 应该和new 语句一样多,以确保没有内存泄漏。所以写这些:

delete [] a->roadId;
delete [] a->lane[0];
delete [] a->lane[1];
delete a; //you've written only this!

注意delete a应该是释放内存时的最后一条语句!

【讨论】:

    【解决方案3】:

    我不是故意的,但这段代码有足够多的问题,几乎很难决定从哪些开始。

    using namespace std;
    

    这是第一个危险信号。我只能说using namespace std; 是个坏主意。对于其他命名空间,这是可以接受的,但对于 std,应始终避免使用 (IMO)。

    struct Intersection
    {
      unsigned short road;
      long long int *roadId;
      short *lane[2];
    };
    

    这让我觉得这是一个设计得很糟糕的结构。 std::vector 是件好事。用它。您可能需要考虑为您的结构类型定义operator&gt;&gt;,而不仅仅是一种愚蠢的数据结构,这样您就可以直接阅读一个。即使你不这样做,从你使用它的方式来看,你真正想要的更像是:

    struct road { 
         long long Id;
         short lane[2];
    };
    
    struct Intersection {
        int road_count;
        road *roads;
    };
    

    然后,您将获得多条道路,每条道路都有自己的数据,而不是两个大小相同的平行阵列必须并行行走。不过std::vector 还是更好。

    int main(int argc, char** argv)
    {
      std::ifstream file;
      cout<<"file: "<<argv[1]<<endl;
      file.open(argv[1], std::ios::in);
    

    您应该通常计划将名称传递给ctor,以便在单个操作中定义和打开它,而不是定义一个ifstream对象然后单独打开它,例如:

      std::ifstream file(argv[1]);
    

    但是,您通常还需要添加一些错误检查,因此您只尝试使用命令行参数作为文件名(如果已通过),如下所示:

      if (argc < 2) {
           std::cerr << "Usage: your_command <filename>\n";
           return EXIT_FAILURE;
      }
    

    那么你就有了定义ifstream的代码。

      while (!file.eof())
    

    这是另一个主要问题。这种形式的循环本质上总是错误的(包括这种情况,从事物的外观来看)。

        cout<<"Start Intersection"<<endl;
        Intersection *a = new Intersection;
    

    似乎没有理由动态分配它。您是否是一名正在恢复(或未恢复)的 Java 或 C# 程序员? Java 要求用户定义类的所有对象都是动态分配的,而 C++ 则不需要。

        file>>a->road;
        a->roadId = new long long int[a->road];
        a->lane[0] = new short[a->road];
        a->lane[1] = new short[a->road];
        cout<<"a->road: "<<a->road<<endl;
        for (int i=0; i<a->road; i++)
        {
          file>>a->roadId[i];
    
          cout<<endl<<"a->roadId["<<i<<"]: "<<a->roadId[i]<<endl;
          file>>a->lane[i][0];
          cout<<"a->lane["<<i<<"][0]: "<<a->lane[i][0]<<endl;
          file>>a->lane[i][1];
          cout<<"a->lane["<<i<<"][1]: "<<a->lane[i][1]<<endl;
        }
    

    我希望将读取数据的代码与显示数据的代码分开。除了诸如家庭作业(或调试)之类的事情之外,您很少希望在阅读时显示大量原始数据。在任何情况下,该类的阅读代码通常应位于 operator&gt;&gt; 中,该类的显示代码应位于 operator&lt;&lt; 中。

        cout<<"Intersection inserted"<<endl;
    

    这似乎是彻头彻尾的谎言。你实际上并没有在任何东西中插入Intersection

        delete a;
    

    当您退出动态分配Intersection 时,您也可以消除这种情况。如果您坚持手动处理所有动态分配,则需要在此之前删除组件以避免内存泄漏(另一个更喜欢std::vector的原因)。

    我知道这听起来可能很消极,这让我有点伤心。一方面,我真的喜欢提出更好的做事方法。同时,这看起来很像家庭作业,我非常不愿意发布更好的代码。我试图提供一些关于更好方法的提示,但意识到它们可能不像你想要的那样具体——我为此道歉,但考虑到这可能是家庭作业,我认为我不能成为更具体。

    【讨论】:

    • 感谢您的详尽评论,非常感谢。我将我的实际代码简化为这段代码,以便突出显示问题。我的实际代码非常复杂,包括数据结构。我在这里不需要动态分配内存,但是在我拥有的代码中没有其他选择。我在编程方面有很多经验,但一段时间以来一直没有联系,因此编程风格不好。您指出的大部分内容已经包含在我的代码中,当我试图减少代码长度时,这些内容悄悄地出现了。非常感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2021-08-11
    • 2021-01-04
    • 2015-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-17
    • 1970-01-01
    相关资源
    最近更新 更多