【问题标题】:How to explain Segmentation fault sometimes happening when dynamically allocating 2D array?如何解释动态分配二维数组时有时会发生分段错误?
【发布时间】:2019-02-05 02:20:07
【问题描述】:

我想要一个函数来初始化带有列和行的简单网格(二维数组),然后每个位置(单元格)就是结构的大小。

我找到了一个解决方案,可以在 main 函数中完成此操作,但在任何其他函数中完成时,在运行到一半后,它在打印 Grid 之前因分段错误而崩溃(与上一段不同)。

但是,如果在初始化部分的后面直接添加打印Grid,之后代码可以正常工作,所有故障都消失了。

我怀疑 main 现在没有初始化 Position 数组,但我将它作为指针传递,我做错了什么?

以下代码分为两部分。第一个有分段错误,第二个没有。唯一不同的是,在第二部分中,用于打印网格的 for 循环在初始化 2d 数组的函数内部。

//SEGMENTATION FAULT

void CreateMap (struct GameGrid *Position, int &Dim_x, int &Dim_y)
{
    cout << "Lets create the game map." << endl;
    cout << "Enter number of Columns: ";
    cin >> Dim_x;
    cout << "Enter number of Rows: ";
    cin >> Dim_y;

    Position = new GameGrid[Dim_x * Dim_y];
}

int main()
{
    struct GameGrid *Position = NULL;
    int Dim_x;
    int Dim_y;

    CreateMap(Position, Dim_x, Dim_y);

    for (int y=0; y < Dim_y; y++)
    {
        cout << setw (20);

        for (int x=0; x < Dim_x; x++)
        {
            cout << Position[x*Dim_y + y].Element;
            cout << char(32);
        }
        cout << endl;
    }

    delete[] Position;
    return 0;
}

//NO FAULTS

void CreateMap (struct GameGrid *Position, int &Dim_x, int &Dim_y)
{
    cout << "Lets create the game map." << endl;
    cout << "Enter number of Columns: ";
    cin >> Dim_x;
    cout << "Enter number of Rows: ";
    cin >> Dim_y;

    Position = new GameGrid[Dim_x * Dim_y]

    for (int y=0; y < Dim_y; y++)
    {
        cout << setw (20);

        for (int x=0; x < Dim_x; x++)
        {
            cout << Position[x*Dim_y + y].Element;
            cout << char(32);
        }
        cout << endl;
    }
}

int main()
{
    struct GameGrid *Position = NULL;
    int Dim_x;
    int Dim_y;

    CreateMap(Position, Dim_x, Dim_y);

    delete[] Position;
    return 0;
}

对于维度 Dim_x=6 和 Dim_y=6(由最终用户选择),网格应如下所示。

A A A A A A
A A A A A A
A A A A A A
A A A A A A
A A A A A A
A A A A A A

此外,当打印网格两次时(一次在函数 CreateMap 中,一次在 main 中),它会打印两次,然后冻结 10 秒并死掉。

【问题讨论】:

    标签: c++ multidimensional-array


    【解决方案1】:

    在您的CreateMap 函数中:

    void CreateMap (struct GameGrid *Position, int &Dim_x, int &Dim_y)
    {
        // ...    
        Position = new GameGrid[Dim_x * Dim_y];
    }
    

    这会修改Position 仅局部变量,它不会改变提供给该参数的调用者值。

    你需要重新设计这个:

    GameGrid *CreateMap(const int Dim_x, const int Dim_y)
    {
        // ...    
        return new GameGrid[Dim_x * Dim_y];
    }
    

    在哪里返回一个你可以捕获的值:

    int main()
    {
      int x, y;
      cout << "Lets create the game map." << endl;
      cout << "Enter number of Columns: ";
      cin >> x;
      cout << "Enter number of Rows: ";
      cin >> y;
    
      GameGrid *Position = CreateMap(x, y);
      // ...
    }
    

    在这些功能之外进行所有输入/输出。记住你的SOLID Principles,只给这个函数一份工作和一份工作。输入和分配是两个工作。

    更好的是:创建一个构造函数,而不是这些 CreateX 函数。这是 C++,您可以充分利用它。

    一如既往:

    每当您遇到奇怪的行为时,请在调试器中单步调试您的代码,以查看执行时各种变量的值。

    【讨论】:

    • 谢谢,它成功了,但是你能不能给我一些关于调用函数继承类型的链接,比如GameGrid *CreateMap?我不知道如何命名那个东西,所以我自己找不到它。我是这方面的新手,所以我想了解更多。
    • "Inherit" 通常表示类的继承,但这不是这里发生的事情,这只是一个返回 GameGrid* 的函数。您还可以编写其他一些具有构造函数的class,例如Game,它具有std::vector&lt;GameGrid&gt; 作为网格本身。试着从标准库容器的角度来考虑你的 C++ 代码,而不是用 new[] 分配的原始指针和数组。
    【解决方案2】:

    虽然您使用指针作为参数,但您仍然是按值传递。

    当尝试通过引用传递时,指针本身不会改变,但它指向的地址处的对象会更新。

    因此,要更新指针,您需要指向指针的指针或指针的引用。否则,通常如已回答的那样,return 用于返回更新后的指针。

    【讨论】:

    • 对不起,我试图这样做,但我在搜索引擎中得到的最远的是:another topic about reference-to-pointer,但无法实现。你能给我一些提示吗?我也在寻找指针对指针,但我对很多用户说这种方法会导致“整个堆内存使用不连续”感到害怕。
    • 函数头是'void CreateMap (struct GameGrid *&Position, int &Dim_x, int &Dim_y)'。
    猜你喜欢
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    • 2021-08-04
    • 2010-12-27
    • 2011-07-28
    • 2014-01-07
    相关资源
    最近更新 更多