【问题标题】:" free(): invalid pointer:" 8-puzzle BFS" free(): 无效指针:" 8-puzzle BFS
【发布时间】:2018-02-19 04:00:12
【问题描述】:

我正在尝试编写一个广度优先搜索程序来解决 8 难题。当我运行以下代码时,出现以下错误:

* `/home/a.out' 中的错误:free():无效指针:0x0000000001f81430 *
中止

我很确定问题在于 this 指针的使用以及我如何存储父节点。有什么帮助吗?

 #include <iostream>
 #include <string>
 #include <iostream>     
 #include <algorithm>    
 #include <vector>       
 #include <queue>
 using namespace std;
 class Node {
 public:

vector<Node> children;
vector<int> puzzle;
vector<int> goal = {1, 2, 3, 4, 5, 6, 7, 8, 0};
Node *parent;

Node(vector<int> _puzzle, Node *_parent){   // constructor for node
    puzzle=_puzzle;
    parent=_parent;
}

void moveUp(){    //function to move up
    int zPos = findZero();
    vector<int> temp = puzzle;
    if ( zPos != 0 || zPos != 1 || zPos != 2 )
    std::swap(temp[zPos], temp[zPos-3]);
    Node child = Node(temp, this);
    children.push_back(child);      
}

void moveDown(){    //function to move down
    int zPos = findZero();
    vector<int> temp = puzzle;
    if ( zPos != 6 || zPos != 7 || zPos != 8 )
    std::swap(temp[zPos], temp[zPos+3]);
    Node child = Node(temp, this);
    children.push_back(child); 
}

void moveRight(){    //function to move right
    int zPos = findZero();
    vector<int> temp = puzzle;
    if ( zPos != 2 || zPos != 5 || zPos != 8 )
    std::swap(temp[zPos], temp[zPos+1]);
    Node child = Node(temp, this);
    children.push_back(child);
}


void moveLeft(){     //function to move left
    int zPos = findZero();
    vector<int> temp = puzzle;
    if ( zPos != 0 || zPos != 3 || zPos != 6 )
    std::swap(temp[zPos], temp[zPos-1]);
    Node child = Node(temp, this);
    children.push_back(child); 
}

void printPuzzle() {    //function to print the puzzle
    int count = 0;
    for (auto i: puzzle) {
    if ( count % 3 == 0)
    std::cout << std::endl;
    std::cout << i << ' ';
    count++;   
}
}

int findZero(){    // function to find the location of zero
    std::vector<int>::iterator it;
    it = find (puzzle.begin(), puzzle.end(), 0);
    auto z = std::distance(puzzle.begin(), it);
    return (int)z;
}

bool isGoal(){  //function to check if goal state is reached
    bool goalFound = false;
    if(puzzle == goal)
    goalFound = true;
    return goalFound;
}

};


bool contains(std::queue<Node> q, Node n){   // checks repeated nodes
    std::queue<Node> tempQ = q;
    bool exist = false;
    while (!tempQ.empty()){
        if (tempQ.front().puzzle == n.puzzle)
        exist = true;
        tempQ.pop();
    }
    return exist;
}

int main()
{
std::vector<int> initial = {3, 5, 8, 1, 0, 4, 2, 7, 6};
Node init = Node(initial, NULL);
std::queue<Node> openList;
std::queue<Node> closedList;
openList.push(init);
bool goalFound = false;
while(!openList.empty() && !goalFound){
    Node currentNode = openList.front();
    closedList.push(currentNode);
    openList.pop();       
    currentNode.moveUp();
    currentNode.moveDown();
    currentNode.moveRight();
    currentNode.moveLeft();

    for (auto i: currentNode.children){
        Node currentChild = i;
        if (currentChild.isGoal()){
            std::cout << "Goal Found." << endl;
            goalFound = true;           
        }
        if (!contains(openList, currentChild) && !contains(closedList, currentChild))
            openList.push(currentChild); 
    }      
}
}

现在我只专注于寻找目标。我还没有实现目标路径并打印最终解决方案。

【问题讨论】:

  • 你到处复制节点,但是你没有一个行为良好的复制构造函数或赋值运算符。您的大多数 parent 指针无效(它们指向已被销毁的旧 currentNode)。
  • 我刚刚注释掉了所有关于父指针的行。我仍然得到同样的错误。也许问题出在其他地方。
  • parent 稍后会联系您。 vectors 是一个非常棒的工具,但是在将指向项目的指针存储在一个中时,你必须保持警惕。更多阅读:en.cppreference.com/w/cpp/container/…stackoverflow.com/questions/6438086/iterator-invalidation-rules
  • 如果不是太不方便的话,您能否更详细地解释一下我哪里出错了。
  • 阅读链接,但一般问题是向量包含您输入的内容的副本。副本的地址与原始地址不同。当您在vector 中移动东西时,项目的地址会根据vector 中的时间而改变。一次交换和parent 指针指向错误的位置。另外,当您向vector 添加内容时,迟早它必须分配更多存储空间并将其当前包含的内容复制到新存储空间中。parent 指针指向旧存储空间,vector 会在它已经完成了。试图访问已删除的内存是不好的。

标签: c++ pointers this breadth-first-search sliding-tile-puzzle


【解决方案1】:
if (zPos != 0 || zPos != 1 || zPos != 2)

应该是

if (zPos != 0 && zPos != 1 && zPos != 2)

其他移动功能的兄弟姐妹也是如此。

TL;DR 解释:

moveUp

if (zPos != 0 || zPos != 1 || zPos != 2)

没有做你想做的事。正文将始终执行,因为zPos 不能同时为 0、1 和 2。例如,如果zPos 为零,那么

if (0 != 0 || 0 != 1 || 0 != 2)
    false  || true   

一个true 就足够了。

这意味着

std::swap(temp[0], temp[0-3]);

将交换 0、-3 并超出范围。 All sorts of weird 可能会在您将内存弄乱时发生,我认为这次您正在覆盖 vector 的存储缓冲区的一些簿记。只要vector 被释放,kaBlamo!

【讨论】:

  • 伟大的收获!谢谢。不要再犯那个错误了。循环运行了一段时间。
  • 我将修改后的代码弹出到调试器中,我能告诉你的最好的就是它没有找到你的目标。如果它在一个价值循环中旋转,这是一个非常大的循环。我建议做我正在做的事情并在whatever debugger came with your development environment 中运行该程序,并留意程序在您认为应该正确运行时向左移动的位置。
  • 当我运行循环只进行几次迭代并在打开列表的顶部打印拼图及其对应的父级时,我得到父级拼图的垃圾值。
  • @pi47 这就是我们在您问题下方的 cmets 中谈论的内容。在不改变存储节点的方式的情况下维护 parent 指针几乎是不可能的。如果您可以避免需要parent 指针,例如递归回溯解决方案,请执行此操作。否则提出一个关于如何保存parent 指针的新问题。我可以想到几种方法来做到这一点,有些容易,有些不那么容易,但超出了这个问题的范围。尝试一次只针对一个问题提出问题。它们对以这种方式追随你的程序员更有用。
  • 知道了。感谢所有的帮助。
猜你喜欢
  • 2012-02-21
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
  • 2013-06-27
  • 2015-03-31
  • 2017-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多