递归回溯 C++、内存地址更改、损坏指针

Recursive Backtracking C++, Memory address changing, damaging pointers

提问人:HarrisonO 提问时间:10/9/2023 更新时间:10/9/2023 访问量:52

问:

我目前正在研究一种用于迷宫生成的递归回溯方法。目前,我正在努力从函数中获取正确的值。在函数中,它返回正确的坐标,但是,当在另一个函数中引用它们时,这些点不再有效并且包含不正确的值。GetNeighbours()RecursiveBacktracking()

我一直在尝试调试它很长一段时间,但似乎无法弄清楚。

任何关于为什么会这样解释的解释都将非常有帮助!

塔克斯

#include <vector>
#include <cstdlib>
#include <stdlib.h> 
#include <algorithm>
#include <ctime>
#include <random>
#include <stack>

class Node{
    public:
        std::vector<Node*> GetNeighbours(Node* baseNode, std::vector<std::vector<Node>> mazeVector){
                
                std::vector<Node*> neighbours;
                //Get south neighbour
                if(baseNode->ypos + 1 < mazeVector.size()){

                    if(!mazeVector.at(baseNode->ypos+1).at(baseNode->xpos).isVisited){
                        neighbours.push_back(&mazeVector.at(baseNode->ypos+1).at(baseNode->xpos));
                    }
                }
                //Get north neighbour
                if(baseNode->ypos - 1 >= 0){

                    if(!mazeVector.at(baseNode->ypos-1).at(baseNode->xpos).isVisited){
                        neighbours.push_back(&mazeVector.at(baseNode->ypos-1).at(baseNode->xpos));
                       // std::cout << neighbours[0]->ypos << ", " << neighbours[0]->xpos;
                    }
                }
                //Get east neighbour
                if(baseNode->xpos + 1 < mazeVector.at(baseNode->ypos).size()){

                    if(!mazeVector.at(baseNode->ypos).at(baseNode->xpos+1).isVisited){
                        neighbours.push_back(&mazeVector.at(baseNode->ypos).at(baseNode->xpos+1));
                       // std::cout << neighbours[0]->ypos << ", " << neighbours[0]->xpos;
                    }
                }
                if(baseNode->xpos -1 >= 0){

                    if(!mazeVector.at(baseNode->ypos).at(baseNode->xpos-1).isVisited){
                        neighbours.push_back(&mazeVector.at(baseNode->ypos).at(baseNode->xpos-1));
                        //std::cout << neighbours[0]->ypos << ", " << neighbours[0]->xpos;
                    }
                }

                std::random_device rd;
                std::mt19937 g(rd());

                std::shuffle(neighbours.begin(), neighbours.end(), g);

                // for(int i = 0; i < neighbours.size(); i++){
                //     std::cout << "Neighbours[" << i << "] before return = (" << neighbours[i]->ypos << ", " << neighbours[i]->xpos << ")" << std::endl;
                //     std::cout << "Memory Address [" << i << "] within function = " << neighbours[i] << std::endl;
                //     std::cout << "Memory Address [" << i << "]within maze = " << &mazeVector[neighbours[i]->ypos][neighbours[i]->xpos] << std::endl;
                // }
                return neighbours;

            }

        bool isVisited = false;
        int ypos;
        int xpos;
      /*  Node(int y, int x, bool visited = false){
            this->ypos = y;
            this-> xpos = x;
            this-> isVisited = visited;
        }
        */


        
};
void PrintMaze(std::vector<std::vector<Node>>& mazeVector){
    for(int i = 0; i < mazeVector.size(); i++){ 
        for (int j = 0; j < mazeVector[i].size(); j++)
        {
            Node* currentNode = &mazeVector.at(i).at(j);
            if(currentNode->isVisited){
                std::cout << 'X';
            }else{
                std::cout << '.';
            }
           // std::cout << &currentNode <<" = (" << currentNode->ypos << ", " << currentNode->xpos <<")";
            
           // std::cout << currentNode.GetNeighbours(currentNode, i, j, mazeVector).size();
        }
        std::cout<<std::endl;
        
    }

} 

void RecursiveBacktracking(std::vector<std::vector<Node>>& maze, int x, int y){
    _sleep(500);
    std::cout<<"------GENERATING------" << std::endl;
    
    std::vector<Node*> stack;
    stack.emplace_back(&maze[0][0]);
    Node* currentNode = stack[0];
    currentNode->isVisited = true;
    while(stack.size() > 0){
        _sleep(3000);
        PrintMaze(maze);
        
        currentNode->isVisited = true;
        std::vector<Node*> neighbours = currentNode->GetNeighbours(currentNode, maze);
        PrintMaze(maze);
        // for(int i = 0; i < neighbours.size(); i++){
        //             std::cout << "Neighbours[" << i << "] after return = (" << neighbours[i]->ypos << ", " << neighbours[i]->xpos  << ")" << std::endl;
        //             std::cout << "Neighbours[" << i << "] Memory after return = (" << neighbours[i] << std::endl;
        //         }
        if(neighbours.size() > 0){
            stack.emplace_back(neighbours[0]);
            std::cout << "Selected neighbour = (" <<  stack[stack.size()-1]->ypos << ", " << stack[stack.size()-1]->xpos << ")" << std::endl;
            //std::cout<< "Selected Neighbour Coords: " << currentNode-> ypos<< ", " << currentNode-> xpos<< std::endl;
            currentNode = stack[stack.size()-1];
        }else{
           
            stack.pop_back();
            currentNode = stack[stack.size()-1];

        }
        for (size_t i = 0; i < stack.size(); i++)
        {
           
            /* code */
        }
        
         std::cout<< "Size while in loop: "<<stack.size() << std::endl;
   }
   std::cout<<stack.size() << std::endl;

}


int main(){
    int length;
    int width;
    std::cout << "Please enter and length and width: " << std::endl;
    std::cin >> length >> width;
    std::cout << "Please enter a seed for maze generation or enter '0' for a random seed: " << std::endl;
    int seed;
    std::cin >> seed;
    if(seed == 0){
        std::srand((unsigned) time(NULL));
    }else{
    std::srand(seed);
    }

    std::vector<std::vector<Node>> mazeVector(length, std::vector<Node>(width));

    for(int i = 0; i < length; i++){
        for (int j = 0; j < width; j++)
        {
            Node currentNode;/* = Node(i, j); */
            currentNode.ypos = i;
            currentNode.xpos = j;
            mazeVector.at(i).at(j) = currentNode;
        }
    }

   PrintMaze(mazeVector);
   RecursiveBacktracking(mazeVector, 0, 0);

   



return 1; 
}



C++ 算法 指针 向量 按引用传递

评论

2赞 PaulMcKenzie 10/9/2023
std::vector<std::vector<Node>> mazeVector-- 您是否知道您正在按值传递它,这意味着该函数正在处理本地副本?当函数返回时,该副本会发生什么情况?
1赞 Some programmer dude 10/9/2023
缩减代码,可能一直缩减到空函数。添加一行或两行,在生成时启用额外的警告并将其视为错误,并在生成时测试代码。如果有效,则再添加一两行。等等。这将使调试导致问题的代码、将其隔离到最小的可重现示例以及解决问题变得更加容易。main
1赞 PaulMcKenzie 10/9/2023
按值传递向量是一个明显的迹象,表明您是一名 C# 或 Java 程序员,被 C++ 在传递参数方面的工作方式绊倒了。当您在 C++ 中传递值时,会在函数中创建一个副本,当该函数退出时,该副本将消失。C#、Java 和其他语言不是以这种方式工作的,因为实际的向量正在被传递和使用。在 C++ 中,若要通过引用传递,必须使用 显式声明它。&
0赞 HarrisonO 10/9/2023
@PaulMcKenzie哈哈,把我读得像一本书!我所需要的只是额外的& 经过微小的调整后它又开始工作了!

答:

3赞 PaulMcKenzie 10/9/2023 #1

这是按值传递的,这意味着这是一个本地副本。mazeVector

std::vector<std::vector<Node>> mazeVector

然后在函数本身中,您正在执行以下操作:

neighbours.push_back(&mazeVector.at(baseNode->ypos).at(baseNode->xpos+1));

您正在将 的临时地址存储在 中,然后最终返回 。当函数返回时,neighborsneighbors

return neighbours;

这将被销毁,因此所有这些地址都不再有效。mazeVector

您应该通过引用而不是按值传递:mazeVector

std::vector<Node*> GetNeighbours(Node* baseNode, std::vector<std::vector<Node>>& mazeVector)

但即使这样,也不能保证你的代码能正常工作。原因是您不应该存储矢量元素的地址。如果向量的大小超出容量,因此必须重新分配内部向量存储器怎么办?您存储的所有这些指针现在都将失效。

评论

1赞 PaulMcKenzie 10/9/2023
更改了措辞。