用于解决 15 个谜题的 C 代码在尝试显示谜题每次更新的路径时会出现分段错误

问题描述 投票:0回答:1

我有一个代码,应该在显示初始状态和目标状态后显示解决 15 个难题的路径。然而,虽然它确实显示了初始状态和目标状态,但它给出了分段错误而不是打印出路径。

下面是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N 4
#define NxN (N*N)
#define TRUE 1
#define FALSE 0

struct node {
    int tiles[N][N];
    int f, g, h;
    short zero_row, zero_column;
    struct node *next;
    struct node *parent;
};

int goal_rows[NxN];
int goal_columns[NxN];
struct node *start,*goal;
struct node *open = NULL, *closed = NULL;
struct node *succ_nodes[4];

void print_a_node(struct node *pnode) {
    int i,j;
    for (i=0;i<N;i++) {
        for (j=0;j<N;j++) 
            printf("%2d ", pnode->tiles[i][j]);
        printf("\n");
    }
    printf("\n");
}

struct node *initialize(char **argv){
    int i,j,k,index, tile;
    struct node *pnode;

    pnode=(struct node *) malloc(sizeof(struct node));
    index = 1;
    for (j=0;j<N;j++)
        for (k=0;k<N;k++) {
            tile=atoi(argv[index++]);
            pnode->tiles[j][k]=tile;
            if(tile==0) {
                pnode->zero_row=j;
                pnode->zero_column=k;
            }
        }
    pnode->f=0;
    pnode->g=0;
    pnode->h=0;
    pnode->next=NULL;
    pnode->parent=NULL;
    start=pnode;
    printf("initial state\n");
    print_a_node(start);

    pnode=(struct node *) malloc(sizeof(struct node));
    goal_rows[0]=3;
    goal_columns[0]=3;

    for(index=1; index<NxN; index++){
        j=(index-1)/N;
        k=(index-1)%N;
        goal_rows[index]=j;
        goal_columns[index]=k;
        pnode->tiles[j][k]=index;
    }
    pnode->tiles[N-1][N-1]=0;
    pnode->f=0;
    pnode->g=0;
    pnode->h=0;
    pnode->next=NULL;
    goal=pnode; 
    printf("goal state\n");
    print_a_node(goal);

    return start;
}

void merge_to_open() { 
    for (int i = 0; i < N; i++) {
        if (succ_nodes[i] == NULL) {
            continue;
        }
        struct node *insert_node = (struct node *) malloc(sizeof(struct node));
        memcpy(insert_node->tiles, succ_nodes[i]->tiles, NxN*sizeof(int));
        insert_node->f = succ_nodes[i]->f;
        insert_node->g = succ_nodes[i]->g;
        insert_node->h = succ_nodes[i]->h;
        insert_node->zero_row = succ_nodes[i]->zero_row;
        insert_node->zero_column = succ_nodes[i]->zero_column;
        insert_node->parent = succ_nodes[i]->parent;

        if (open == NULL) {
            open = insert_node;
            continue;
        }

        struct node *temp = open;

        int status = FALSE;

        while (temp != NULL && temp->next != NULL) {
            if (insert_node->f < temp->next->f) {
                insert_node->next = temp->next;
                temp->next = insert_node;
                status = TRUE;
                break;
            }
            temp = temp->next;
        }

        if (status == FALSE) {
            temp->next = insert_node;
        }
    }
}

void swap(int row1,int column1,int row2,int column2, struct node * pnode){
    int tile = pnode->tiles[row1][column1];
    pnode->tiles[row1][column1]=pnode->tiles[row2][column2];
    pnode->tiles[row2][column2]=tile;
}

int manhattan(int entry, int row, int column) {
    for (int i = 0; i < NxN; i++) {
        for (int j = 0; j < NxN; j++) {
            if(goal->tiles[i][j] == entry) {
                return abs(row - i) + abs(column - j);
            }
        }
    }
}

void update_fgh(int t) {
    struct node *pnode = succ_nodes[t];
    
    if (pnode -> parent != NULL) {
        pnode->g = pnode->parent->g + 1;
    } else {
        pnode->g = 1;
    }

    int misplaced = 0, distance = 0, correct = 0;
    
    for (int i = 0; i < NxN; i++) {
        for (int j = 0; j < NxN; j++) {
            correct++;
            if (pnode->tiles[j][i] != correct) {
                misplaced++;
            }

            if (pnode->tiles[j][i] == 0) {
                distance = 0;
            } else {
                distance = manhattan(pnode->tiles[j][i], j, i);
            }
        }
    }

    if (misplaced > distance) {
        pnode->h = misplaced;
    } else {
        pnode->h = distance;
    }

    pnode->f = pnode->g + pnode->h;
}

void move_down(struct node * pnode){
    if (pnode->zero_row + 1 < N) {
        swap(pnode->zero_row, pnode->zero_column, pnode->zero_row + 1, pnode->zero_column, pnode);
        pnode->zero_row++;
    } else {
        pnode = NULL;
    }
}

void move_right(struct node * pnode){
    if (pnode->zero_column + 1 < N) {
        swap(pnode->zero_row, pnode->zero_column, pnode->zero_row, pnode->zero_column + 1, pnode);
        pnode->zero_column++;
    } else {
        pnode = NULL;
    }
}

void move_up(struct node * pnode){
    if (pnode->zero_row - 1 > -1) {
        swap(pnode->zero_row, pnode->zero_column, pnode->zero_row - 1, pnode->zero_column, pnode);
        pnode->zero_row--;
    } else {
        pnode = NULL;
    }
}

void move_left(struct node * pnode){
    if (pnode->zero_column - 1 > -1) {
        swap(pnode->zero_row, pnode->zero_column, pnode->zero_row, pnode->zero_column - 1, pnode);
        pnode->zero_column--;
    } else {
        pnode = NULL;
    }
}

void expand(struct node *selected) {
    for (int i = 0; i < N; i++) {
        succ_nodes[i] = NULL;
    }

    move_down(succ_nodes[0]);
    move_right(succ_nodes[1]);
    move_up(succ_nodes[2]);
    move_left(succ_nodes[3]);

    for (int i = 0; i < N; i++) {
        update_fgh(i);
    }
}

int nodes_same(struct node *a,struct node *b) {
    int flg=FALSE;
    if (memcmp(a->tiles, b->tiles, sizeof(int)*NxN) == 0)
        flg=TRUE;
    return flg;
}
 
void filter(int i, struct node *pnode_list){ 
    struct node *pnode = succ_nodes[i];
    struct node *temp = pnode_list;
    while (temp != NULL) {
        if (nodes_same(pnode, temp)) {
            pnode = NULL;
            return;
        }
        temp = temp->next;
    }
}

int main(int argc,char **argv) {
    int iter,cnt;
    struct node *copen, *cp, *solution_path;
    int ret, i, pathlen=0, index[N-1];

    solution_path=NULL;
    start=initialize(argv);
    open=start; 

    iter=0; 
    while (open!=NULL) {
        copen=open;
        open=open->next;

        if(nodes_same(copen,goal)){
            do{
                copen->next=solution_path;
                solution_path=copen;
                copen=copen->parent;
                pathlen++;
            } while(copen!=NULL);
            printf("Path (length=%d):\n", pathlen); 
            copen=solution_path;

            break;
        }
        expand(copen);

        for(i=0;i<4;i++){
            filter(i,open);
            filter(i,closed);
        }

        merge_to_open();

        copen->next=closed;
        closed=copen;

        iter++;
        if(iter %1000 == 0)
            printf("iter %d\n", iter);
    }
    return 0;
}

我使用这些命令行参数来运行程序:

2 3 0 4 1 6 7 8 5 9 10 12 13 14 11 15

当我运行程序的 gdb 调试时,它会打印出以下内容(我在程序中作为 pnode 传递的值是 succ_nodes[0]):

Program received signal SIGSEGV, Segmentation fault.
0x0000555555555940 in move_down (pnode=0x0) at problem1.c:172
172             if (pnode->zero_row + 1 < N) {

我假设所有带有 pnode 语句的移动函数都会发生这种情况。你能帮我想办法解决这个问题吗?

c struct segmentation-fault sliding-tile-puzzle
1个回答
0
投票

我看到

move_down()
是从一个地方
expand()
调用的,并传入了
succ_nodes[0]
。您在对
move_down()
的调用上方看到了什么?

我看到

expand()
有一个函数未使用的输入参数。
expand()
到底应该做什么?

我认为你需要退后一步并理解这个程序应该做什么。在你理解它之前你无法“修复”它。编写程序大纲,并用散文解释要采取的步骤,然后使代码与解释相匹配。

最后,拥有更明显的名称会有所帮助。什么是“曼哈顿”?什么是“fgh”(如“update_fgh”)?

© www.soinside.com 2019 - 2024. All rights reserved.