简体   繁体   English

回溯算法,堆栈溢出错误,尽管堆分配

[英]Backtrack algorithm, Stack overflow error, despite heap allocation

I'm currently working on a program that has to solve a 10x10 char maze, for example this one:我目前正在开发一个必须解决 10x10 字符迷宫的程序,例如这个:

      1   2   3   4   5   6   7   8   9  10
___________________________________________
 1|   +  []   +  []   +  []   +   +   +  []
 2|   +  []   +   +  []   +   +  []  []  []
 3|   +   +  []  []  []   +  []  []   +   +
 4|  []  []  []  []   +   +   +  []  []   +
 5|   +  []   +  []   +  []   +   +   +  []
 6|   +   +   +   +   +   +  []  []   +  []
 7|  []   +   +   +  []  []   +   +   +  []
 8|   +   +   +  []   +   +   +  []  []   +
 9|   +   +   +  []  []   +   +  []  []   +
10|   +  []   +  []   +   +  []   +   +   +

Ignore the numbers, they are just coordinates.忽略数字,它们只是坐标。 As for [] it's just the way the maze is printed.至于[]这只是迷宫的打印方式。 In actuality wherever there's a + then that means path, wherever there's [] that means there's an obstacle.实际上,只要有+就意味着路径,只要有[]就意味着有障碍。

I'm using the backtrack algorithm:我正在使用回溯算法:

void backtrack(int curX, int curY, char(*char_maze)[10], int position)
{
    if (curX < 0 || curY < 0 ||
        curX > 9 || curY > 9) {
        //out of bounds
        return;
    }
    Node tmp;
    tmp.x = curX, tmp.y = curY;
    queue(&head, &tmp);
    position++;
    if (char_maze[curX][curY] == finish) {
        //destination found TODO print path
        printf("route found");
    }
    if (char_maze[curX][curY] == path) {
        char_maze[curX][curY] = visited;
    }
    backtrack(curX, curY - 1, char_maze, position);
    backtrack(curX - 1, curY, char_maze, position);
    backtrack(curX, curY + 1, char_maze, position);
    backtrack(curX + 1, curY, char_maze, position);

    char_maze[curX][curY] = path;
    if (position) {
        del_nth(head, position);
    }
    if (!position) {
        del_first(&head);
    }
    position--;
}

The correct route will consist of a linked list, here's a node of that list:正确的路由将包含一个链表,这是该列表的一个节点:

typedef struct coords {
    int     x;
    int     y;
    struct coords * next;
}Node;

whenever backtrack(...) stumbles over a passable cell, it's supposed to mark it as visited and add it to the list.每当backtrack(...)偶然发现一个可通过的单元格时,它应该将其标记为已访问并将其添加到列表中。 Adding to the list is done by these 2 functions:添加到列表是由这两个函数完成的:

void queue(Node ** head, Node * object)
{
    Node * tmp = (Node *)malloc(sizeof(Node)); //this is the problematic line
    *tmp = *object;
    Node * last = get_last(*(head));
    if (!last) {
        (*head) = tmp;
        tmp->next = NULL;
    }
    else {
        last->next = tmp;
        tmp->next = NULL;
    }
}

and

Node * get_last(Node * head)
{
    while (1) {
        if (head) {
            head = head->next;
        }
        else {
            return NULL;
        }
    }
return head;
}

and also under the appropriate conditions backtrack(...) should unmark a cell and delete it from the list.并且在适当的条件下backtrack(...)应该取消标记单元格并将其从列表中删除。 Deletion is done using these 2 functions:删除是使用这两个函数完成的:

void del_nth(Node * head, int index)
{
    Node * previous;
    for (int i = 0; i < index - 1; i++) {
        head = head->next;
    }
    previous = head;
    head = head->next;
    previous->next = head->next;
    free(head);
}

and

void del_first(Node ** head)
{
    Node * del = (*head);
    (*head) = (*head)->next;
    free(del);
}

path, visited, finish and so on are const char -s, which represent the cells of the maze. path, visited, finish等都是const char -s,代表迷宫的单元格。

backtrack(...)

is called with 2 coordinates set by the user, the maze itself and position which is set to 0 .使用用户设置的 2 个坐标调用,迷宫本身和设置为0 position

Now that I explained how the code works, the problem.现在我解释了代码的工作原理,问题来了。 I've ran this code through the Visual Studio Debugger and I got a Stack overflow (parameters: 0x00000001, 0x00492FFC).我已经通过 Visual Studio 调试器运行了这段代码,但出现了Stack overflow (parameters: 0x00000001, 0x00492FFC). exception on this line这一行的例外

Node * tmp = (Node *) malloc(sizeof(Node)); 

which is a part of the queue(...) function.这是queue(...)函数的一部分。 This doesn't make any sense to me, since malloc() allocates on the heap.这对我来说没有任何意义,因为malloc()在堆上分配。 I'm stumped, I'm out of explanations, I have no idea why this happens.我很难过,我无法解释,我不知道为什么会这样。 I included all of the code used in the backtrack(...) function because the problem may actually be there.我包含了backtrack(...)函数中使用的所有代码,因为问题实际上可能就在那里。 It wouldn't be the first time a debugger pointed out a wrong line.这不是调试器第一次指出错误的行。 Anyway, many thanks for your help in advance.无论如何,非常感谢您的帮助。

You function should return the path it found.您的函数应该返回它找到的路径。 It also should return immediately if the current location is not an open space.如果当前位置不是开放空间,它也应该立即返回。 It also should stop whenever a solution is found.只要找到解决方案,它也应该停止。

HINT: In most recursive algorithms, the return value is used to stop recursion, so recursive functions usually return something of interest, like the result of the operation.提示:在大多数递归算法中,返回值用于停止递归,因此递归函数通常返回一些感兴趣的东西,比如操作的结果。

Example:例子:

Node* backtrack(int curX, int curY, char(*char_maze)[10], int position)
{
    Node* node = NULL;

    // return as fast as possible for
    if (curX < 0 || curY < 0 || curX > 9 || curY > 9) 
    {
        return NULL;
    }
    if (position > 100)  // 10 * 10 cells.
    {
        // should not reach this point.
        printf("iteration depth exceeded maximum limit!!\n")
        return NULL;
    }

    if (char_maze[curX][curY] == finish) 
    {
        printf("route found");
        node = malloc(sizeof(Node));
        if (node)
        {
            node->x = curX;
            node->y = curY;
            node->next = NULL;
        }
        else
        {
            printf("*** ERROR *** malloc returns NULL (1)!!!\n");
        }

        return node;  // this return point is what triggers the backtrack chaining
                      // of positions
    }
    if (char_maze[curX][curY] != path) // nothing to do
    {
        return NULL;
    }

    // mark current location as being worked on.
    char_maze[curX][curY] = visited;

    // now try possible moves, stop looking as soon as a path is found.
    if ((node = backtrack(curX, curY - 1, char_maze, position + 1) != NULL
        || (node = backtrack(curX - 1, curY, char_maze, position + 1) != NULL
        || (node = backtrack(curX, curY + 1, char_maze, position + 1) != NULL
        || (node = backtrack(curX + 1, curY, char_maze, position + 1) != NULL)
    {
        // path found, add current position to the head of the list
        Node* p = malloc(sizeof(Node));
        if (p)
        {
            p->x = curX;
            p->y = curY;
            p->next = node;
            node = p;
        }
        else
        {
            // out of memory, free whatever was allocated before returning.
            printf("*** ERROR *** malloc returns NULL (2)!!!\n");
            while (node)
            {
                p = node->next;
                free(node);
                node = p;
            }
        }
    }

    char_maze[curX][curY] = path;  // clean up.

    return node; // return path found (or not found);
}

NOTE: I have not compiled this code, but this should help you complete your program.注意:我没有编译这段代码,但这应该可以帮助你完成你的程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM