为啥我会出现分段错误?我正在尝试解决迷宫问题中的老鼠
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];
// ...
【讨论】:
以上是关于为啥我会出现分段错误?我正在尝试解决迷宫问题中的老鼠的主要内容,如果未能解决你的问题,请参考以下文章