为啥我会出现分段错误?我正在尝试解决迷宫问题中的老鼠

Posted

技术标签:

【中文标题】为啥我会出现分段错误?我正在尝试解决迷宫问题中的老鼠【英文标题】:why am I getting segmentation fault? I am trying to solve the rat in a maze problem为什么我会出现分段错误?我正在尝试解决迷宫问题中的老鼠 【发布时间】:2021-03-09 15:25:55 【问题描述】:

为什么会出现分段错误?我正在尝试解决迷宫问题中的老鼠。 下面是给我分段错误的代码 可能有一些错误将二维数组传递给函数,但对我来说似乎没问题 我已经在函数 rinm 中应用了基本条件,并从 main() 传递了解矩阵以及用户输入矩阵。

bool rinm(int** maze,int** sol,int n, int x, int y)

    if(x==n-1 && y==n-1)
    
            sol[x][y]=1;

        //print the path
        for (int i = 0; i < n; ++i)
        
            /* code */
            for (int j = 0; j < n; ++j)
            
                cout<<sol[i][j]<<" ";

            

            cout<<endl;
        
        return true;
    
    else if(x<0 || y<0 || x>=n || y>=n || maze[x][y]==0)
    
        return false;
    
    
    sol[x][y]=1;

    bool up=rinm(maze,sol,n,x-1,y);
    bool down=rinm(maze,sol,n,x+1,y);
    bool right=rinm(maze,sol,n,x,y+1);
    bool left = rinm(maze,sol,n,x,y-1);
   
    sol[x][y]=0;

    if(up||down||right||left)
    
        return true;
    

这是我的主要功能。

 int main()
    
        int n;
        cin>>n;
        int** maze=new int*[n];//rows
        for (int i = 0; i < n; ++i)
        
            maze[i]=new int [n]; // columns
        
        
        for (int i = 0; i < n; ++i)
        
            for(int j=0; j<n;j++)
            
                cin>>maze[i][j];
            
        
    
        int** sol=new int*[n];
        for (int i = 0; i < n; ++i)
        
            sol[i]=new int [n]; // columns
        
        for (int i = 0; i < n; ++i)
        
            for(int j=0; j<n;j++)
            
                sol[i][j]=0;
            
        
        bool path=rinm(maze,sol,n,0,0);
        if(path==false)
            cout<<"path doesnot exist\n";
    
        return 0;
    
    

我哪里错了?

【问题讨论】:

这个循环将无限工作,因为您没有存储任何访问过的状态数组。假设输入是2 1 1 0 1,那么你通过 up 和 down 函数调用不断地重新访问 1 你能指定rat in a maze problem是什么吗? @risingStark 你能详细说明我需要修改什么吗?我已经添加了基本条件以及何时需要返回 false.... @risingStark 你能详细说明我需要修改什么吗?我已经添加了基本条件以及何时需要返回 false.... 在调试器中运行时会发生什么 - 您可以看到失败的行和变量的值 【参考方案1】:

问题是不断重新访问相同的单元格,因为您没有检查您是否是第一次访问一个单元格。

例如对于输入:

2
1 1
0 1

我将输入(x, y)的移动序列,你可以看到它会陷入无限循环。

(0, 0) 
    -> (-1, 0) (up function call, returns false since x < 0)
    -> (1, 0) (down function call, return false since maze[1][0] = 0)
    -> (0, 1) 
           -> (-1, 1) (up function call, returns false since x < 0)
           -> (1, 1) (down function call, solution found. Print sol matrix)
           -> (0, 2) (right function call, returns false since y >= 2)
           -> (0, 0) (left function call)

问题就在这里。现在你回到(0, 0) 并且递归继续运行而没有任何终止。这会导致递归堆栈分配大量内存,您会得到 Segmentation Fault

我希望你能理解这里的问题。如果您仍有疑问,只需在进入循环后立即打印(x, y),您就会看到这种情况发生。

这是我对代码所做的更改。这是更正后的代码。这将打印到达目的地的所有可用路径。 如果sol[x][y] == 1,则该函数返回false,这意味着您之前也访问过单元格(x, y)

bool rinm(int** maze,int** sol,int n, int x, int y)

    if(x==n-1 && y==n-1)
    
            sol[x][y]=1;

        //print the path
        for (int i = 0; i < n; ++i)
        
            /* code */
            for (int j = 0; j < n; ++j)
            
                cout<<sol[i][j]<<" ";

            

            cout<<endl;
        
        return true;
    
    else if(x<0 || y<0 || x>=n || y>=n || maze[x][y]==0 || sol[x][y]==1)
    
        return false;
    
    
    sol[x][y]=1;

    bool up=rinm(maze,sol,n,x-1,y);
    bool down=rinm(maze,sol,n,x+1,y);
    bool right=rinm(maze,sol,n,x,y+1);
    bool left = rinm(maze,sol,n,x,y-1);
   
    sol[x][y]=0;

    if(up||down||right||left)
    
        return true;
    
    return false;


要打印到目的地的任何一条路径,您可以保留一个全局变量并在找到任何路径时初始化该变量,然后如果该变量已初始化,则再次返回 false。下面是一个路径路径的代码。
int c = 0;
bool rinm(int** maze,int** sol,int n, int x, int y)

    if(x==n-1 && y==n-1)
    
        c = 1;
            sol[x][y]=1;

        //print the path
        for (int i = 0; i < n; ++i)
        
            /* code */
            for (int j = 0; j < n; ++j)
            
                cout<<sol[i][j]<<" ";

            

            cout<<endl;
        
        return true;
    
    else if(x<0 || y<0 || x>=n || y>=n || maze[x][y]==0 || sol[x][y]==1 || c == 1)
    
        return false;
    

    sol[x][y]=1;

    bool up=rinm(maze,sol,n,x-1,y);
    bool down=rinm(maze,sol,n,x+1,y);
    bool right=rinm(maze,sol,n,x,y+1);
    bool left = rinm(maze,sol,n,x,y-1);
   
    sol[x][y]=0;

    if(up||down||right||left)
    
        return true;
    
    return false;

为了便于理解,这里列出了一些变化。

【讨论】:

但是对于 n=4 1 0 0 0 1 1 1 1 1 0 1 1 1 0 1 1 的好友,我使用此代码获得了额外的输出。 @BikramjitDas 你能发一些截图吗,因为我只得到了上述测试用例的一个输出。我得到的输出是`1 0 0 0 1 1 1 0 0 0 1 0 0 0 1 1 '【参考方案2】:

避免使用原生二维数组。用简单的 1d valarray 或向量替换它们,并使用您自己的简单方法访问它的元素,该方法将 x 和 y 坐标转换为简单的索引。你会从许多头痛中解脱出来......

class Maze

    private:
    std::valarray<int> _data;
    int _width, _height;

    public:
    Maze(int width, int height) : _data(width * height)
    
        _width = width;
        _height = height;
    

    int& item(int x, int y)
    
        return _data[y * _width + x];
    

    // ...

【讨论】:

以上是关于为啥我会出现分段错误?我正在尝试解决迷宫问题中的老鼠的主要内容,如果未能解决你的问题,请参考以下文章

为啥在此 C++ 代码中出现分段错误?

为啥会出现分段错误/如何重载运算符?

为啥这个 AT&T 汇编代码会出现分段错误?

为啥在此代码中调用虚拟方法时会出现分段错误?

由于无效写入导致的分段错误

为啥这个字符会出现分段错误?