Нужна помощь в исправлении ошибки сегментации в C при использовании алгоритма поиска в ширину

#c

#c

Вопрос:

Я использую BFS, чтобы попытаться найти путь через лабиринт, который я создал. Лабиринт представляет собой 2d-массив размером 6×6, состоящий из тире, который выглядит следующим образом:

 XpX--X
X---X-
XXX---
X---X-
X--XXX
-----S
 

Тире — это пустые пробелы, а крестики — стены. P — это начальный пробел, а S — конечный пробел. Я получаю ошибку сегментации и не уверен на 100%, почему. Если бы кто-нибудь мог это понять, это было бы большое спасибо. Я новичок в кодировании, поэтому любая помощь приветствуется.

 #include <iostream>
#include <stack>
#include <fstream>
#include <queue>

using namespace std;

struct Pos
{
  int x;
  int y;
  Pos *prev;
};

Pos start;
Pos finish;

string maze [6][6];
bool visited[6][6];

queue<Pos> mazeQueue;
int current;

void read()
{
  int x = 0, y = 0;
  char c;
  char str[256];
  ifstream is("maze.txt");
  
  while (is.get(c))
  {
    if (x < 6)
    {
      maze[y][x] = c;
      x  ;
    }
    else
    {
      y  ;
      maze[y][x] = c;
      x = 0;
    }
  }

  for(int i = 0; i < 6; i  )
  {
      for(int j = 0; j < 6; j  )
      {
        cout << " " << maze[i][j] << " ";
        visited[i][j] = false;

        if (maze[i][j] == "p")
        {
          start.x = i;
          start.y = j;
          start.prev = NULL;
          visited[i][j] = true;
        }

        if (maze[i][j] == "S")
        {
          finish.x = i;
          finish.y = j;
          finish.prev = NULL;
        }

        if (maze[i][j] == "X")
        {
          visited[i][j] = true;
        }
      }
    cout<<"n";
  }

  cout << endl << endl;
}

void run()
{
  Pos *current;
  mazeQueue.push(start);

  while (!mazeQueue.empty())
  {
    current = amp;mazeQueue.front();
    mazeQueue.pop();

    if (current -> x == finish.x amp;amp; current -> y == finish.y)
    {
      current = current -> prev;

      while (current -> prev != NULL)
      {
        maze[current -> x][current -> y] = "|";
        current = current -> prev;
      }

      for (int i = 0; i < 6; i  )
      {
        for (int j = 0; i < 6; j  )
        {
          cout << maze[i][j] << " ";
        }
        cout << endl;
      }
      break;
    }
    else
    {
      
      if ((current -> y   1 < 6) amp;amp; (!visited[current -> x][current -> y   1]))
      {
        visited[current -> x][current -> y   1] = true;
        Pos temp;
        temp.x = current -> x;
        temp.y = current -> y   1;
        temp.prev = current;
        mazeQueue.push(temp);
      }
    
      if ((current -> y - 1 >= 0) amp;amp; (!visited[current -> x][current -> y - 1]))
      {
        visited[current -> x][current -> y - 1] = true;
        Pos temp;
        temp.x = current -> x;
        temp.y = current -> y - 1;
        temp.prev = current;
        mazeQueue.push(temp);
      }

      if ((current -> x - 1 >= 0) amp;amp; (!visited[current -> x - 1][current -> y]))
      {
        visited[current -> x - 1][current -> y] = true;
        Pos temp;
        temp.x = current -> x - 1;
        temp.y = current -> y;
        temp.prev = current;
        mazeQueue.push(temp);
      }

      if ((current -> x   1 < 6) amp;amp; (!visited[current -> x   1][current -> y]))
      {
        visited[current -> x   1][current -> y] = true;
        Pos temp;
        temp.x = current -> x   1;
        temp.y = current -> y;
        temp.prev = current;
        mazeQueue.push(temp);
      }
      
    }
  } 
}


int main()
{
  read();
  run();
}
 

Комментарии:

1. В первом while случае вы записываете в массив, когда x = 6 .

2. Может быть, вы хотите поставить x = 0; before maze[y][x] = c; вместо after.

Ответ №1:

В вашей read функции есть несколько проблем.

У вас нет никакой проверки ошибок, поэтому, если файл не открывается, вы все равно попытаетесь прочитать его.

Когда вы читаете символ, вы не проверяете его значение. Когда вы дойдете до конца строки, вы прочитаете n символ и продолжите весело добавлять его в свой лабиринт. Поскольку вы никогда не проверяете, достигли ли вы конца лабиринта, вы можете продолжить чтение access после конца maze , что, например, вызовет ошибку segfault .

Основная проблема заключается в том, что вы неправильно обрабатываете x приращение. Перед назначением необходимо выполнить сброс x maze[y][x] . Однако это тело цикла можно упростить, обработав опрокидывание после записи в текущую ячейку.

   while (is.get(c))
  {
    maze[y][x] = c;
    if (  x == 6) {
      x = 0;
        y;
    }
  }
 

(Я не добавил проверки на наличие недопустимых символов или достижение конца лабиринта — это оставлено в качестве упражнения для читателя.)

Другие области для улучшения включают отказ от использования жестко заданных размеров ( 6 вместо этого используйте именованную константу), использование глобальных переменных (все они могут быть инкапсулированы в класс) и переход от массивов в стиле C к стандартным библиотечным контейнерам — std::vector или std::array .