【问题标题】:Dynamically allocating and accessing memory from an array of pointers contained within a struct in C++从 C++ 结构中包含的指针数组动态分配和访问内存
【发布时间】:2016-02-01 18:51:15
【问题描述】:

很抱歉标题过长,但是……它确实说要具体……无论如何!我正在制作一种旨在解决滑块益智游戏的算法。为此,我需要在节点中存储游戏板的所有可能变化。每个游戏板状态都存储在一个节点中,该节点还包含指向其父节点(即其当前状态之前的状态)及其所有子节点(从其当前状态可用的所有可能状态)的指针。这是我构建的节点结构:

struct node
{
    //Attributes
    char gameBoardState[5][4];
    node* parent;
    int numChildren;
    node* childArray[10];

    //Constructor
    node(char pGameState[][4], node* pParent = NULL, int pNumChildren = 0, node* pChildArray[] = NULL)
    {
        //For each row i
        for (int i = 0; i < 5; i++)
        {
            //For each column j
            for (int j = 0; j < 4; j++)
            {
                //Set each block equal to this
                gameBoardState[i][j] = pGameState[i][j];
            }
        }
    }
};

我的问题在这部分代码中,纯粹是为了测试我是否可以正确访问数据等(我已经设计了实际移动片段的函数,但尚未实现它们):

//Sample board state
char sampleBoard[5][4];
char sampleBoard2[5][4];
//Sample character
char sample = 'a';
char sample2 = 'z';
//Initialize the sample board
for (int i = 0; i < 5; i++)
{
    for (int j = 0; j < 4; j++)
    {
        sampleBoard[i][j] = sample;
        sampleBoard2[i][j] = sample2;
        sample++;
        sample2--;
    }
}

//Test
cout << "\n\nERROR BEGINS\n\n";

//Create first node
node top = node(sampleBoard);
//Create a child node
top.childArray[top.numChildren] = new node(sampleBoard2, &top);

//Test
cout << "\n\nERROR ENDS\n\n";

无论出于何种原因,ERROR cmets 之间的行都会产生内存访问错误。我查看了有关指针、数组、结构及其组合的各种 C++ 教程。我还尝试在“新节点”调用中省略“&top”;没有帮助。我只是没有看到我的代码是如何在内存访问中产生这个错误的。我还在这里查看了十几个答案,但没有一个答案似乎适用于我的情况。我觉得我错过了一些相当明显的东西。任何帮助,即使它只是重定向到我以某种方式忽略的有效答案?提前致谢!

【问题讨论】:

  • 停止使用数组的数组并切换到std::vectors of std::strings,所有问题都会消失。

标签: c++ arrays pointers struct runtime-error


【解决方案1】:

问题其实很简单,你从来​​没有初始化过numChildren

因此,尝试说出top.childArray[top.numChildren] ... 可能会导致numChildren 评估为一些荒谬(可能为负数)的数字。

这里更大的问题是您的代码设计不佳。它非常类似于 C,因为您使用了大量原始指针和数组,其中大小信息是分开的。此外,跟踪这些指针的生命周期的责任在于您,而不是自动发生。

我建议你考虑用std::vectorstd::string重构你的代码,它们提供索引操作以及.size(),你的代码会变得更安全。

您还可以将char gameBoardState[5][4]; 封装到一个class GameBoard 中,该class GameBoard 可以在构造时任意调整大小(像以前一样使用vector)。如果您决定使用不同的游戏板进行测试,这还有一个额外的好处,即您无需到处更改代码。

【讨论】:

  • 如上,不敢相信我忽略了这么简单的事情。至于使用 std::vector 和 std::string ,这绝对是我至少应该考虑的未来。不过,就目前而言,与我一起工作的这个小组的主要问题之一是资源利用。尽管我同意向量与数组的性能损失在大多数情况下不足以担心,但我正在与之合作的其他人对此非常热衷。不过,我绝对感谢详细的附加批评! :)
  • @MalkavAmonra:很高兴能提供帮助。我会反击你的队友。过早的优化是万恶之源,使用原始指针和 c 风格的数组是过早的优化。您会惊讶于 std::vector 在每个应用程序中的运行效果。
【解决方案2】:

top.childArray[top.numChildren] = new node(sampleBoard2, &top);

numChildren 从未初始化。这意味着它有一些垃圾价值。它很可能是 [0, 9] 之外的值,因此您正在访问您不拥有的内存,它是 UB,并且将/可能导致内存访问错误。

【讨论】:

  • 哇,我简直不敢相信我忘记将构造函数中的参数值实际传递给结构属性!我知道这将是显而易见的事情。感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 2013-04-18
  • 1970-01-01
  • 2012-07-16
  • 2019-10-20
  • 2020-05-17
  • 2014-02-23
  • 2021-03-14
  • 1970-01-01
相关资源
最近更新 更多