C中的分段错误(递归永不结束)

时间:2015-02-20 17:32:42

标签: c recursion backtracking maze

我正在尝试解决这个问题:

  

鉴于迷宫,它希望找到从给定起始位置到奶酪位置的路径(目标   位置)。迷宫可视化为包含墙(表示为1)或自由方式的矩形网格   (表示为0)。程序必须打印从起始位置到结束位置的路径。   目标位置将存储值9。在该程序中,假设循环路径不是   可能在网格中。 (您无需检查循环路径。)

这就是我在做的事情:

#include<stdio.h>

typedef struct Maze
{
    int ** values;
    int size;
} Maze;

int traverse (Maze M, int n, int posi, int posj, char **path_so_far,
        int past_i, int past_j)
{
    int k;
    printf("Hello\n");
    int i=0;
    int temp;  

    if (M.values[posi][posj] == 9)
    {
        path_so_far[i][0] = posi + '0';
        path_so_far[i][1] = posj + '0';
        path_so_far[i][2] = '\0';
        printf("%s\n", path_so_far[i]); 
        i++;
        return 1;    
    }
    else if (posi - 1 >= 0 && M.values[posi - 1][posj] != 1
            && posi - 1 != past_i)
    {      
        temp = traverse(M, n, posi - 1, posj, path_so_far, past_i, past_j);
        if (temp == 1)
        {
            path_so_far[i][0] = posi + '0';
            path_so_far[i][1] = posj + '0';
            path_so_far[i][2] = '\0';      
            printf("%s\n", path_so_far[i]);               
            i++;
            return 1;
        }
    }
    else if (posi + 1 < n && M.values[posi + 1][posj] != 1 && posi + 1 != past_i)
    {
        temp = traverse(M, n, posi + 1, posj, path_so_far, past_i, past_j);
        if (temp == 1)
        {
            path_so_far[i][0]=posi+'0';
            path_so_far[i][1]=posj+'0';
            path_so_far[i][2]='\0';  
            printf("%s\n",path_so_far[i]);                    
            i++;
            return 1;
        }
    }
    else if(posj - 1 >=0 && M.values[posi][posj - 1] !=1 && posj - 1 != past_j)
    { 
        temp = traverse(M, n, posi, posj - 1, path_so_far, past_i, past_j);
        if(temp==1)
        {
            path_so_far[i][0] = posi + '0';
            path_so_far[i][1] = posj + '0';
            path_so_far[i][2] = '\0';   
            printf("%s\n", path_so_far[i]);                  
            i++;
            return 1;
        }
    }
    else if (posj + 1 < n && M.values[posi][posj + 1] != 1 && posj + 1 != past_j)
    { 
        temp = traverse(M, n, posi, posj + 1, path_so_far, past_i, past_j);
        if(temp == 1)
        {
            path_so_far[i][0] = posi + '0';
            path_so_far[i][1] = posj + '0';
            path_so_far[i][2] = '\0';     
            printf("%s\n", path_so_far[i]);                   
            i++;
            return 1;
        }
    }
    else
    {
        return 0;
    }                     
}

迷宫M已被照顾,即它在另一个功能中初始化,这里未示出。我使用参数traverse调用(M, 0, 0, 0, path, 0, 0),但它会产生分段错误。我尝试添加printf("Hello\n"),如我的代码的第10行所示,以查看错误发生的位置;它大量打印“Hello”,最后给出segmentation fault。我做错了什么?

3 个答案:

答案 0 :(得分:2)

您的代码设计中存在一些重要错误。其中一个是i变量使用(参见我的评论)。另一种是打印路径步骤的方法:首先,在从递归traverse返回之后打印第i步是错误的(因为所有后续步骤都已打印在递归里面!);但是,在递归之前你也无法打印(因为你不知道你是否在正确的道路上)。那么,怎么做呢?

好吧,你应该在path_so_far[i]标记下一步,然后进入递归。您还需要将递增的步骤编号i+1传递给递归步骤,以便该函数始终知道它正在执行哪个步骤,以及它应填充的path_so_far项。

当您到达目标点时,您只需打印整个累积的path_so_far,此刻为最终路径,然后返回1以获得成功。这个结果渗透了最终导致计算结束的递归。

另一方面,如果您发现无法进一步移动,则会因失败而返回0。递归traverse的结果应该会导致您在当前级别测试另一种可能性。

所以:

int traverse(Maze M, int n, int posi, int posj,char **path_so_far, int i)
{
    int temp;
    if(M.values[posi][posj]==9)  // target found
    {
        int j;                   // print the complete path
        for(j=0; j<i; j++)
            printf("%s\n",path_so_far[j]);
        return 1;
    }

    // mark the current position as 'visited'

    M.values[posi][posj] = 2;

    // try next possible move
    // test if adjacent cell is empty or is target

    if(posi-1>=0 && (M.values[posi-1][posj]==0 || M.values[posi-1][posj]==9))
    {      
        path_so_far[i][0]=posi-1+'0';
        path_so_far[i][1]=posj+'0';
        path_so_far[i][2]='\0';      
        temp=traverse(M,n,posi-1,posj,path_so_far,i+1);
        if(temp==1)
            return 1;
    }

    if(posi+1<n && (M.values[posi+1][posj]==0 || M.values[posi+1][posj]==9))
    {      
        path_so_far[i][0]=posi+1+'0';
        path_so_far[i][1]=posj+'0';
        path_so_far[i][2]='\0';      
        temp=traverse(M,n,posi+1,posj,path_so_far,i+1);
        if(temp==1)
            return 1;
     }

     // similary for posj-1 and posj+1...

    if(posj-1>=0 && (M.values[posi][posj-1]==0 || M.values[posi][posj-1]==9))
    {
        ...
    }

    if(posj+1<n && (M.values[posi][posj+1]==0 || M.values[posi][posj+1]==9))
    {
        ...
    }

    // none of the tested paths returned success...
    // mark the current position as no longer 'visited'

    M.values[posi][posj] = 0;

    //return the failure status

    return 0;
}

答案 1 :(得分:1)

您似乎使用参数past_ipast_j来避免加倍,但是当您递归时,您不会传递前一个位置的坐标,因为这样的方案有效。例如,看来这......

temp = traverse(M, n, posi - 1, posj, path_so_far, past_i, past_j);

......应该......

temp = traverse(M, n, posi - 1, posj, path_so_far, posi, posj);

。如果不这样做,你可以(并且确实)在两个位置之间来回(看起来可能在0,1和1,1之间)。您的代码还有其他问题,例如没有正确记录路径,但分段错误可能是由于递归深度足以耗尽堆栈空间。

答案 2 :(得分:1)

并非traverse()中的所有路径都返回值。包含

的每个代码块
if(temp == 1)
    {
    ...
    return 1;
    }

时,

将无法返回任何函数值

(temp != 1)

您必须在编译器上启用所有警告...尤其是当事情不起作用时。