迷宫构造器问题 [线程 1:EXC_BAD_ACCESS(代码=1,地址=0x8)]

Posted

技术标签:

【中文标题】迷宫构造器问题 [线程 1:EXC_BAD_ACCESS(代码=1,地址=0x8)]【英文标题】:Maze Constructor Issues [Thread 1: EXC_BAD_ACCESS (code=1, address=0x8)] 【发布时间】:2019-02-21 21:15:35 【问题描述】:

当我运行我的程序时,一切都会编译,直到 Maze 类被实例化。我收到警告说Code will never be executed 在我的 主.cpp。编译器 (Xcode) 将我重定向到The LLVM Compiler Infrastructure,在line 1590 上显示Thread 1: EXC_BAD_ACCESS (code=1, address=0x8)。表明这一点的代码块是:

template <class _Tp, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
void
vector<_Tp, _Allocator>::push_back(const_reference __x)

    if (this->__end_ != this->__end_cap()) //Thread 1: EXC_BAD_ACCESS (code=1, address=0x8)
    
        __RAII_IncreaseAnnotator __annotator(*this);
        __alloc_traits::construct(this->__alloc(),
                                  _VSTD::__to_raw_pointer(this->__end_), __x);
        __annotator.__done();
        ++this->__end_;
    
    else
        __push_back_slow_path(__x);

main.cpp:

#include "Maze.h"
#include <iostream>
#include <string>

int main(int argc, char* argv[])

    std::cout << "-------------\tMaze\t-------------\n\n";

    Maze maze(10);
    std::string direction;

    while(!true)
    
        //Code will never be executed warning HERE
        std::cout << "Input a character to move your avatar in the maze and press RETURN\n";
        std::cout << "(w = UP, s = DOWN, a = LEFT, d = RIGHT)\n";
        std::cin >> direction;
        maze.takeTurn(direction);
        maze.printMe();
    

    return 0;

我的头文件:

#ifndef MAZE_H
#define MAZE_H

#include <vector>
#include <string>

extern const std::string Up;
extern const std::string Down;
extern const std::string Left;
extern const std::string Right;

class Maze

private:
    char avatarToken; //character that represents the avatar
    char emptyToken; //character that represents empty space in the maze
    char wallToken; //character that represents a wall
    char exitToken; //character that represents an exit - where you quit the game
    char stairsUpToken; //character that represents stairs that take you to an UPPER level
    char stairsDownToken; //character that represents a Hole that takes you a LOWER level
    char bossToken; //character that represents a boss that kills you (you lose/exit the game)

    int dim; //width of this square maze
    std::vector< std::vector<char> > grid; //a vector of vectors of characters

    int avatarRow; //row position of our avatar from zero to dim-1 (NOT from 1 to dim)
    int avatarCol; //column position of our avatar from zero to dim-1 (NOT from 1 to dim)

public:
    //constructor
    Maze(int newDim = 4,
         char _avatarToken = 'A',
         char _emptyToken = ' ',
         char _wallToken = '*',
         char _exitToken = 'E',
         char _stairsUpToken = '^',
         char _stairsDownToken = 'V',
         char _bossToken = 'B');

    void printMe();
    bool takeTurn(std::string direction); //move the avatar in the requested direction if possible
;

#endif

我的实现文件:

#include "Maze.h"
#include "Keyboard.h" //contains global variables: Up, Down, Left, Right
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>

//1st constructor
Maze::Maze(int newDim,
           char _avatarToken,
           char _emptyToken,
           char _wallToken,
           char _exitToken,
           char _stairsUpToken,
           char _stairsDownToken,
           char _bossToken) : dim(newDim),
                              avatarToken(_avatarToken),
                              emptyToken(_emptyToken),
                              wallToken(_wallToken),
                              exitToken(_exitToken),
                              stairsUpToken(_stairsUpToken),
                              stairsDownToken(_stairsDownToken),
                              bossToken(_bossToken)

    //place avatar location in center of maze
    this->avatarRow = newDim / 2;
    this->avatarCol = newDim / 2;

    //initialize top wall of grid
    for(int i = 0; i < this->dim; i++)
        this->grid[0].push_back(this->wallToken);

    //initialize middle of grid
    for(int j = 1; j < this->dim - 1; j++)
        for(std::vector<char>::iterator it = this->grid[j].begin(); it < this->grid[j].end(); it++)
            it == this->grid[j].begin() ||
            it == this->grid[j].end() ? this->grid[j].push_back(this->wallToken) :
            this->grid[j].push_back(this->emptyToken);

    //initialize bottom wall of grid
    for(int l = 0; l < this->dim; l++)
        this->grid[dim - 1].push_back(this->wallToken);

    //place exit token in random spot in the maze
    srand( (unsigned int) time(0)); //random seed for exit token placement in maze
    int rand_wall = rand() % 4 + 1; //determine which wall exit token is on
    int rand_placement = rand() % this->dim + 1; //placement of exit on wall
    switch(rand_wall)
    
        case 1:
            this->grid[0][rand_placement] = this->exitToken;
            break;
        case 2:
            this->grid[rand_placement][0] = this->exitToken;
            break;
        case 3:
            this->grid[this->dim - 1][rand_placement] = this->exitToken;
            break;
        case 4:
            this->grid[rand_placement][this->dim - 1] = this->exitToken;
            break;
    

    //place stairs up token in random spot in the maze
    srand( (unsigned int) time(0)); //random seed for stairs up token placement in maze
    rand_wall = rand() % 4 + 1; //determine which wall stairs up token is on
    rand_placement = rand() % this->dim + 1; //placement of stairs up on wall
    switch(rand_wall)
    
        case 1:
            //check to see if element is occupied by exit token
            if(this->grid[0][rand_placement] != this->exitToken)
                this->grid[0][rand_placement] = this->stairsUpToken;
            break;
        case 2:
            //check to see if element is occupied by exit token
            if(this->grid[rand_placement][0] != this->exitToken)
                this->grid[rand_placement][0] = this->stairsUpToken;
            break;
        case 3:
            //check to see if element is occupied by exit token
            if(this->grid[this->dim - 1][rand_placement] != this->exitToken)
                this->grid[this->dim - 1][rand_placement] = this->stairsUpToken;
            break;
        case 4:
            //check to see if element is occupied by exit token
            if(this->grid[rand_placement][this->dim - 1] != this->exitToken)
                this->grid[rand_placement][this->dim - 1] = this->stairsUpToken;
            break;
    

    //place stairs down token in random spot in the maze
    srand( (unsigned int) time(0)); //random seed for stairs down token placement in maze
    rand_wall = rand() % 4 + 1; //determine which wall stairs down token is on
    rand_placement = rand() % this->dim; //placement of stairs down on wall
    switch(rand_wall)
    
        case 1:
            //check to see if element is occupied by exit token or stairs up token
            if(this->grid[0][rand_placement] != this->exitToken ||
               this->grid[0][rand_placement] != this->stairsUpToken)
            
                this->grid[0][rand_placement] = this->stairsDownToken;
            
            break;

        case 2:
            //check to see if element is occupied by exit token or stairs up token
            if(this->grid[rand_placement][0] != exitToken ||
               this->grid[rand_placement][0] != this->stairsUpToken)
            
                this->grid[rand_placement][0] = this->stairsDownToken;
            
            break;

        case 3:
            //check to see if element is occupied by exit token or stairs up token
            if(this->grid[this->dim - 1][rand_placement] != this->exitToken ||
               this->grid[this->dim - 1][rand_placement] != this->stairsUpToken)
            
                this->grid[this->dim - 1][rand_placement] = this->stairsDownToken;
            
            break;

        case 4:
            //check to see if element is occupied by exit token or stairs up token
            if(this->grid[rand_placement][this->dim - 1] != this->exitToken ||
               this->grid[rand_placement][this->dim - 1] != this->stairsUpToken)
            
                this->grid[rand_placement][this->dim - 1] = this->stairsDownToken;
            
            break;
    

    //place boss token in random spot inside the maze
    srand( (unsigned int) time(0)); //random seed for boss token placement in maze
    rand_placement = rand() % this->dim; //placement of boss token
    switch(rand_wall)
    
        case 1:
            //check to see if element is occupied by exit token or stairs up token
            if(this->grid[0][rand_placement] != this->exitToken ||
               this->grid[0][rand_placement] != this->stairsUpToken)
            
                this->grid[0][rand_placement] = this->stairsDownToken;
            
            break;

        case 2:
            //check to see if element is occupied by exit token or stairs up token
            if(this->grid[rand_placement][0] != exitToken ||
               this->grid[rand_placement][0] != this->stairsUpToken)
            
                this->grid[rand_placement][0] = this->stairsDownToken;
            
            break;

        case 3:
            //check to see if element is occupied by exit token or stairs up token
            if(this->grid[this->dim - 1][rand_placement] != this->exitToken ||
               this->grid[this->dim - 1][rand_placement] != this->stairsUpToken)
            
                this->grid[this->dim - 1][rand_placement] = this->stairsDownToken;
            
            break;

        case 4:
            //check to see if element is occupied by exit token or stairs up token
            if(this->grid[rand_placement][this->dim - 1] != this->exitToken ||
               this->grid[rand_placement][this->dim - 1] != this->stairsUpToken)
            
                this->grid[rand_placement][this->dim - 1] = this->stairsDownToken;
            
            break;
    


//print maze row by row
void Maze::printMe()

    //rows
    for(int m = 0; m < this->dim; m++)
    
        //columns
        for(int n = 0; n < this->dim; n++)
        
            //print avatar token
            if(m == this->avatarRow && n == this->avatarCol)
                std::cout << this->avatarToken;
            else
                std::cout << this->grid[m][n];
        
        std::cout << std::endl;
    


//update location of the avatar
bool Maze::takeTurn(std::string _direction)

    if(_direction == Up && this->grid[this->avatarRow - 1][this->avatarCol] != this->wallToken)
    
        --this->avatarRow;
        if(this->grid[this->avatarRow - 1][this->avatarCol] == this->exitToken ||
           this->grid[this->avatarRow - 1][this->avatarCol] == this->bossToken ||
           this->grid[this->avatarRow - 1][this->avatarCol] == this->stairsUpToken ||
           this->grid[this->avatarRow - 1][this->avatarCol] == this->stairsDownToken)
        
            std::cout << "You exited the maze.\n";
            return true;
        
        else return false;
    
    else if(_direction == Down && this->grid[this->avatarRow + 1][this->avatarCol] != this->wallToken)
    
        ++this->avatarRow;
        if(this->grid[this->avatarRow + 1][this->avatarCol] == this->exitToken ||
           this->grid[this->avatarRow + 1][this->avatarCol] == this->bossToken ||
           this->grid[this->avatarRow + 1][this->avatarCol] == this->stairsUpToken ||
           this->grid[this->avatarRow + 1][this->avatarCol] == this->stairsDownToken)
        
            std::cout << "You exited the maze.\n";
            return true;
        
        else return false;
    
    else if(_direction == Left && this->grid[this->avatarRow][this->avatarCol - 1] != this->wallToken)
    
        --this->avatarCol;
        if(this->grid[this->avatarRow][this->avatarCol - 1] != this->exitToken ||
           this->grid[this->avatarRow][this->avatarCol - 1] != this->bossToken ||
           this->grid[this->avatarRow][this->avatarCol - 1] != this->stairsUpToken ||
           this->grid[this->avatarRow][this->avatarCol - 1] != this->stairsDownToken)
        
            std::cout << "You exited the maze.\n";
            return true;
        
        else return false;
    
    else if(_direction == Right && this->grid[this->avatarRow][this->avatarCol + 1] != this->wallToken)
    
        ++this->avatarCol;
        if(this->grid[this->avatarRow][this->avatarCol + 1] != this->exitToken ||
           this->grid[this->avatarRow][this->avatarCol + 1] != this->bossToken ||
           this->grid[this->avatarRow][this->avatarCol + 1] != this->stairsUpToken ||
           this->grid[this->avatarRow][this->avatarCol + 1] != this->stairsDownToken)
        
            std::cout << "You exited the maze.\n";
            return true;
        
        return false;
    
    else return false;

编辑:从class Maze 中删除了不必要的类成员。

【问题讨论】:

不是访问错误的原因,但请仔细查看while(!true)。仅当条件为真时才会运行 while 循环。当你评估条件时,你得到的是真还是假? 有趣的趣事:无论你在构造函数的成员初始化器列表中指定成员的顺序是什么,成员仍然会按照它们在类定义中声明的顺序进行初始化。我不认为这会在这里咬你,但我也无法构建你的代码来找出答案。键盘的东西不见了。 @NathanOliver 指出,刚刚更改了我的 IDE 中的代码,使用外部布尔值作为 while 条件。 @user4581301 我应该如何给网格容量?我应该在构造函数中声明另一个向量并将其设置为等于网格吗? (也固定rand_placement) 如:std::vector&lt;std::vector&lt;char&gt; &gt; _grid(this-&gt;dim); this-&gt;grid = _grid; 【参考方案1】:
this->grid[0].push_back(this->wallToken);

在为grid 分配任何存储空间之前将项目推入grid[0]。没有grid[0] 可以安全地调用push_back

可能的解决方案:

在成员初始化器中预分配所有内容。

Maze::Maze(int newDim,
           char _avatarToken,
           char _emptyToken,
           char _wallToken,
           char _exitToken,
           char _stairsUpToken,
           char _stairsDownToken,
           char _bossToken) : avatarToken(_avatarToken),
                              emptyToken(_emptyToken),
                              wallToken(_wallToken),
                              exitToken(_exitToken),
                              stairsUpToken(_stairsUpToken),
                              stairsDownToken(_stairsDownToken),
                              bossToken(_bossToken),    
                              dim(newDim), // moved
                              grid(dim, std::vector<char>(dim)) //added

然后使用运算符[] 而不是将角色推入迷宫。例如

for(int i = 0; i < this->dim; i++)
    this->grid[0][i] = this->wallToken;

再想一想,

grid(dim, std::vector<char>(dim, _wallToken))

将通过将网格中的每个空间初始化为墙来消除用于设置边界墙的循环的需要。为您节省一些工作。

还要留意

int rand_placement = rand() % this->dim + 1; 

rand_placement 可以等于 dim 并且 vectors 仅在 0 到 dim-1 之间有效。这使得

this->grid[rand_placement][0] = this->exitToken;

和其他人写的越界。

【讨论】:

我在构造函数实现中初始化grid 时遇到了困难。我在构造函数的第一行将其写为grid(dim, std::vector&lt;char&gt;(dim));,但我收到错误Type 'std::vector&lt;std::vector&lt;char&gt; &gt;' does not provide a call operator

以上是关于迷宫构造器问题 [线程 1:EXC_BAD_ACCESS(代码=1,地址=0x8)]的主要内容,如果未能解决你的问题,请参考以下文章

如何打造多路无死角的“迷宫”?

[ZJOI2018]迷宫

ios 13 SwiftUI向后导航时如何避免导航视图内的TabView应用崩溃

bzoj5213: [Zjoi2018]迷宫

迷宫寻路系列常用算法逻辑探究

迷宫问题