在C中使用BFS解决迷宫-分段故障

时间:2020-03-26 17:20:45

标签: c

我正在尝试使用BFS解决迷宫,但是遇到了分段错误。谁能帮我弄清楚为什么会这样吗?另外,如果您发现我的代码还有其他问题吗?我的if语句用于检查迷宫中是否存在该点以及该点是否存在空白。我也正在使用DFS解决迷宫,但是seg错误发生在resolve_bfs期间。而且,除了solve.c之外的所有东西都交给了我的教授,所以我唯一想编辑的就是solve.c

解决。c

#include <stdio.h>
#include <stdlib.h>
#include "maze.h"
#include "stack.h"
#include "queue.h"

int solve_bfs(maze * the_maze){
  Queue Q= initQueue();
  enqueue(Q, the_maze->entry);
  while(!emptyQueue(Q)){
    coord to_explore= dequeue(Q);
    if(to_explore.row == the_maze->exit.row && to_explore.col == the_maze->exit.col){
      print_maze(the_maze);
      free(Q);
      return 1;
    }
    else{
      the_maze->data[to_explore.row][to_explore.col]= 'o';

      if(to_explore.row-1 >= 0){
    if(the_maze->data[to_explore.row-1][to_explore.col] == ' '){
      coord new;
      new.row= to_explore.row-1;
      new.col= to_explore.col;
      enqueue(Q, new);
    }
      }
      if(to_explore.col+1 < the_maze->width){
    if(the_maze->data[to_explore.row][to_explore.col+1]== ' '){
      coord new;
      new.row= to_explore.row;
      new.col= to_explore.col+1;
      enqueue(Q, new);
    }
      }
      if(to_explore.row+1 < the_maze->height){
    if(the_maze->data[to_explore.row+1][to_explore.col]== ' '){
      coord new;
      new.row= to_explore.row+1;
      new.col= to_explore.col;
      enqueue(Q, new);
    }
      }
      if(to_explore.col-1 >= 0) {
      if(the_maze->data[to_explore.row][to_explore.col-1]== ' '){
    coord new;
    new.row= to_explore.row;
    new.col= to_explore.col-1;
    enqueue(Q, new);
      }
      }
    }
    if(emptyQueue(Q)){
    print_maze(the_maze);
    free(Q);
    return 0;
    }
  }
}
int solve_dfs(maze * the_maze){
  Stack s= initStack();
  push(s, the_maze->entry);
  while(!emptyStack(s)){
    coord to_explore= pop(s);
    if(to_explore.row == the_maze->exit.row && to_explore.col == the_maze->exit.col){
      print_maze(the_maze);
      free(s);
      return 1;
    }
    else{
      if(to_explore.row-1 >= 0){
      if(the_maze->data[to_explore.row-1][to_explore.col]== ' '){
    coord new;
    new.row= to_explore.row-1;
    new.col= to_explore.col;
    push(s, new);
      }
      }
      if(to_explore.col+1 < the_maze->width){
      if(the_maze->data[to_explore.row][to_explore.col+1]== ' '){
    coord new;
    new.row= to_explore.row;
    new.col= to_explore.col+1;
    push(s, new);
      }
      }
      if(to_explore.row+1 < the_maze->height){
      if(the_maze->data[to_explore.row+1][to_explore.col]== ' '){
    coord new;
    new.row= to_explore.row+1;
    new.col= to_explore.col;
    push(s, new);
      }
      }
      if(to_explore.col-1 >= 0){
      if(the_maze->data[to_explore.row][to_explore.col-1]== ' '){
    coord new;
    new.row= to_explore.row;
    new.col= to_explore.col-1;
    push(s, new);
      }
      }
    }
    if(emptyStack(s)){
      print_maze(the_maze);
      free(s);
      return 0;
    }
  }

}
void print_maze(maze * the_maze){
  the_maze->data[the_maze->entry.row][the_maze->entry.col]='S';
  the_maze->data[the_maze->exit.row][the_maze->exit.col]='F';
  for(int i=0; i<the_maze->width; i++){
    for(int j=0; j<the_maze->height; j++){
      printf("%s",the_maze->data[i][j]);
    }
  }
}
coord * make_coord(int r, int c){
  coord * coord= malloc(sizeof(coord));
  coord->row = r;
  coord->col = c;
  return coord;

}
void print_coord(coord c){
  printf("(%d,%d)",c.row, c.col);
}

Maze.c


#include <stdio.h>
#include <stdlib.h>
#include "maze.h"

/**********************************************************
 create_maze
 creates a new maze from the input file characters
*********************************************************/
maze * create_maze(FILE *in) {
  // create maze
  maze * new_maze = (maze *) malloc(sizeof(maze));

  // read first line of in
  int start_row;
  int start_col;
  int end_row;
  int end_col;
  int num_rows;
  int num_cols;

  // start line
  char * line = malloc(sizeof(char)*100);   // start buffer out at 100
  size_t num_read;

  getline(&line, &num_read, in);
  if(sscanf(line, "%d %d %d %d %d %d", &num_rows, &num_cols, &start_row, &start_col, &end_row, &end_col) != 6) {
    fprintf(stderr, "Maze file format invalid. Top line must include 6 numbers.\n");
    return NULL;
  }
  // if any are negative values, return NULL
  if(start_row < 0 || start_col < 0 || end_row < 0 || end_col < 0 || num_rows < 0 || num_cols < 0) {
    fprintf(stderr, "Maze file format invalid. Maze file numbers in first row must be non-negative.\n");
    return NULL;
  }

  // make sure start_row is in bounds
  if(start_row >= num_rows) {
    fprintf(stderr, "Maze file format invalid. Start row must be < num rows in maze.\n");
    return NULL;
  }

  // make sure end_row is in bounds
  if(end_row >= num_rows) {
    fprintf(stderr, "Maze file format invalid. End row must be < num rows in maze.\n");
    return NULL;
  }

  // make sure start_col is in bounds
  if(start_col >= num_cols) {
    fprintf(stderr, "Maze file format invalid. Start col must be < num cols in maze.\n");
    return NULL;
  }

  // make sure end_col is in bounds
  if(end_col >= num_cols) {
    fprintf(stderr, "Maze file format invalid. Start col must be < num cols in maze.\n");
    return NULL;
  }

  // assign maze members
  new_maze->entry.row = start_row;
  new_maze->entry.col = start_col;
  new_maze->exit.row = end_row;
  new_maze->exit.col = end_col;
  new_maze->width = num_cols;
  new_maze->height = num_rows;

  // allocate memory for maze data
  new_maze->data = (char **) malloc(sizeof(char *)*num_rows);
  int i;
  for(i=0; i<num_rows; i++) {
    new_maze->data[i] = (char *) malloc(sizeof(char)*num_cols);
  }

  // get characters from file, one line at a time
  size_t num_vals_read = 0;
  for(i=0; i<num_rows; i++) {
    num_vals_read = getline(&line, &num_read, in);
    if(num_vals_read != num_cols + 1) { //account for newline character
      fprintf(stderr, "Maze file format invalid. Found %d chars on line %d and the width is %d.\n", 
          (num_vals_read-1), i, new_maze->width);
      return NULL;
    }
    // parse out line
    int j;
    for(j=0; j<num_cols; j++) {
      if(line[j] != ' ' && line[j] != '*') {
    fprintf(stderr, "Maze file format invalid. Maze file data must contain spaces and stars. Read %c.\n", line[j]);
    return NULL;
      }
      new_maze->data[i][j] = line[j];
    }
  }
  // try to read more data
  char c;
  if((c = fgetc(in)) != EOF) {
    fprintf(stderr, "Maze file format invalid. Too many characters past %d rows.\n", num_rows);
    return NULL;
  }

  free(line);
  return new_maze;
}

/******************************************************
 free_maze
 frees memory used by the_maze 
 ******************************************************/
void free_maze(maze * the_maze) {
  // first free the data
  // need to free rows of data, then data
  int i;
  for(i = 0; i < the_maze->height; i++) {
    free(the_maze->data[i]);
  }
  free(the_maze->data);
  free(the_maze);
  return;
}

Queue.c

#include <stdio.h>
#include <stdlib.h>
#include "queue.h"

/* initializes empty queue */
Queue initQueue() {
  Queue q = malloc(sizeof(QueueType));
  q->head = 0;
  q->tail = 0;
  return q;
}

/* returns 1 if queue is empty and 0 otherwise */
int emptyQueue(Queue Q) {
  return (Q->head == Q->tail);
}
/* puts data item d into queue */
void enqueue(Queue Q, QueueData d) {
  if(full(Q)) {
    printf("Queue is full. Did not add item.\n");
    return;
  }
  Q->tail++;
  Q->tail = Q->tail % MAX_Q; // in case it goes off array
  Q->data[Q->tail] = d;
}

/* removes data item from queue */
QueueData dequeue(Queue Q) {
  if(emptyQueue(Q)) {
    printf("Attempting to remove from empty queue\n");
    exit(1);
  }
  Q->head++;
  Q->head = Q->head % MAX_Q; // in case it goes off array
  return Q->data[Q->head];
}

/* checks if queue is full */
int full(Queue Q) {
  return (Q->tail + 1) % MAX_Q == Q->head;
}

/* freeQueue */
void freeQueue(Queue Q) {
  free(Q);
}

Main.c


#include <stdio.h>
#include <stdlib.h>
#include "maze.h"

#define NUM_PARAMS 2

/* prototypes */
void usage(char * executable);

/***********************************************************************
 * main
   executable_name input_filename.txt
   opens input_filename.txt for reading
   creates maze object
   runs the maze solver
   frees maze
*********************************************************************/
// function completed for the CS 305 students: DO NOT MODIFY (Unless you find a bug)   
int main(int argc, char * argv[]) {
  if(argc != NUM_PARAMS) {
    usage(argv[0]);
    return EXIT_FAILURE;
  }    

  // open file for reading
  FILE *fp = NULL;
  fp = fopen(argv[1], "r");
  if(fp == NULL) {
    fprintf(stderr, "Error opening input file %s. Exiting.\n", argv[1]);
    return EXIT_FAILURE;
  }

  // create maze objects
  // need 2 since we are running BFS on one (which modifies the
  // maze with the path marker character)
  // need clean copy of maze for DFS
  maze * the_maze = create_maze(fp);
  rewind(fp); // resets file pointer to beginning of file
  maze * the_maze2 = create_maze(fp);

  // done with file at this point
  fclose(fp);
  fp = NULL;  

  // check maze to see if it was created successfully
  if(the_maze == NULL || the_maze2 == NULL) {
    fprintf(stderr, "Error creating maze data structure\n");
    return EXIT_FAILURE;
  }

  // run breadth-first-search on maze
  printf("\nSolving using breadth-first search.\n");
  int a = solve_bfs(the_maze);

  // run depth-first-search on maze
  printf("\nSolving using depth-first search:\n");
  int b = solve_dfs(the_maze2);

  printf("\ncan solve BFS: %d, can solve DFS: %d\n\n", a, b);

  // free memory and exit
  free_maze(the_maze);
  free_maze(the_maze2);
  return EXIT_SUCCESS;
}

/*********************************************************
 usage
 prints error message to user
**********************************************************/
void usage(char * executable) {
  printf("Usage: \n%s maze_file.txt\n", executable);
}

stack.c

#include <stdio.h>
#include <stdlib.h>
#include "stack.h"

/* initializes a new stack */
Stack initStack() {
  Stack s = (Stack) malloc(sizeof(StackType));
  s->top = NULL;
  return s;
}

/* empty returns 0 if S is empty and non-zero if S is not empty */
int emptyStack(Stack S) {
  return (S->top == NULL);
}

/* pushes d to S */
void push(Stack S, StackData d) {
  Node * n = (Node *)malloc(sizeof(Node));
  n->data = d;
  n->next = S->top;
  S->top = n;
}

/* pops top item from S */
StackData pop(Stack S) {
  if(emptyStack(S)) {
    printf("Stack is empty. Attempting to pop an empty stack. Exiting program.\n");
    exit(1);  // exiting program
  }
  // there is data to pop
  StackData toReturn = S->top->data;
  Node * tmp = S->top;  // in order to free this later
  S->top = S->top->next;  // move pointer to next item in stack
  free(tmp);
  return toReturn;
}

/* frees stack memory */
void freeStack(Stack S) {
  while(!emptyStack(S)) {
    pop(S);
  }
  free(S);
}

queue.h


#ifndef QUEUE_H
#define QUEUE_H

#include "maze.h"

#define MAX_Q 5000  // 1 more than what can be stored in the queue
                    // in this application, the mazes are on the small
                    // side

/* data to store into queue */
typedef coord QueueData;  // putting coordinates into queue

/* queue data structure */
typedef struct QueueTag QueueType;
typedef struct QueueTag* Queue; // pointer to queue struct
                                // so when it is passed, the values
                                // can be updated in functions

struct QueueTag {
  int head;
  int tail;
  QueueData data[MAX_Q]; // space for items in queue
};

/* function prototypes on queues */
Queue initQueue();
int emptyQueue(Queue Q);
void enqueue(Queue Q, QueueData d);
QueueData dequeue(Queue Q);
int full(Queue Q);
void freeQueue();

#endif

maze.h

#ifndef MAZE_H
#define MAZE_H

/* struct definition for coord */
typedef struct coord {
  int row;
  int col;
} coord;

/* struct definition for maze */
typedef struct maze {
  coord entry;
  coord exit;
  int width;
  int height;
  char ** data;
} maze;

/* prototypes */
/* in maze.c */
maze * create_maze(FILE *in);
void free_maze(maze * the_maze);

/* in solve.c */
int solve_bfs(maze * the_maze);
int solve_dfs(maze * the_maze);
void print_maze(maze * the_maze);
coord * make_coord(int r, int c);
void print_coord(coord c);

#endif

stack.h


#ifndef STACK_H
#define STACK_H

#include "maze.h"

#define BAD {-1, -1}  // coordinate off maze

/* data to store into stack */
typedef coord StackData;  

/* stack data structures */
typedef struct NodeTag Node;
typedef struct StackTag StackType;
typedef struct StackTag* Stack;

/* linked list implementation of stacks */
struct NodeTag {
  StackData data;
  Node *next;
};

struct StackTag {
  Node * top;
};

/* function prototypes on stacks */
Stack initStack();
int emptyStack(Stack S);
void push(Stack S, StackData d);
StackData pop(Stack S);
void freeStack(Stack S);

#endif

2 个答案:

答案 0 :(得分:1)

假设索引从零开始,您需要修复边界检查

# incorrect
to_explore.col+1 =< the_maze->width
# correct
to_explore.col+1 < the_maze->width

类似的情况是检查to_explore.row 强调的文本

答案 1 :(得分:1)

错误在print_maze函数中。

void print_maze(maze * the_maze){
  the_maze->data[the_maze->entry.row][the_maze->entry.col]='S';
  the_maze->data[the_maze->exit.row][the_maze->exit.col]='F';
  for(int i=0; i<the_maze->width; i++){
    for(int j=0; j<the_maze->height; j++){
      printf("%s",the_maze->data[i][j]);
    }
  }

data[i]代表第i行,因此我应该遍历高度。 data[i][j]代表j行中的第ith个元素,因此j应该遍历宽度。您需要在for循环中交换高度和宽度。

void print_maze(maze * the_maze){
  the_maze->data[the_maze->entry.row][the_maze->entry.col]='S';
  the_maze->data[the_maze->exit.row][the_maze->exit.col]='F';
  for(int i=0; i<the_maze->height; i++){
    for(int j=0; j<the_maze->width; j++){
      printf("%s",the_maze->data[i][j]);
    }
  }
}