c++中的free()中出错

Error in free() in c++

本文关键字:出错 中的 free c++      更新时间:2023-10-16

我认为这与以下内容有关:如果将指针保存到堆栈上分配的对象,则该对象超出范围,然后通过该指针修改某些内容,则可能会损坏其他人的内存。

我正在执行RandomMaze和Pacman游戏。我有一张地图(迷宫),上面有一个二维阵列,我把走廊、墙壁、食物和牧师和鬼魂的位置放在那里。在那张地图上,我知道帕克曼是否可以向东、向北等移动。。然后使用opengl,我必须"制作动画":它从屏幕上的x,y像素移动。。。。

所以在主文件中,我有一个全局变量,叫做Maze m;然后我把它传给一个八哥。moveEast(m,s);(屏幕的宽度和高度都是用来绘制的)。问题是(我认为)我在操作中使用了m,不知怎么的,它调用了free()指令,因为超出了范围(我想是这样)。

任何想法都会被采纳。。

vector<Ghost> playingGhosts;
Maze m;
Pacman myPacman;
Screen s ( WIDTH,HEIGHT);
Ghost Blinky, Pinky, Inky, Pokey;
int ghosts = 1;
long last_t=0;
int main (int argc, char *argv[])
{
    srand(time(NULL));
    m.setupMaze(ROWS, COLUMNS, LEVEL);
    m.printMaze();
    //myPacman.set_position(m.getRows(),0);
    /*Esta función es la que inicializa la GLUT y negocia con el sistema de ventanas para abrir una. Los parámetros deben ser los mismos argc y argv,
     * sin modificar, de la función main(). Además, Glut entiende una serie de parámetros que pueden ser pasados por línea de comandos.*/
    glutInit(&argc, argv);
    /*En esta ocasión, utilizamos GLUT_DOUBLE en vez de GLUT_SIMPLE. Esto hace posible la utilización de la técnica de “double buffer”, con la utilizamos
     * dos buffers para pintar en uno mientras se visualiza el otro. Con esto conseguimos una mayor fluidez en escenas.
     */
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    //Posición x e y de la esquina superior izquierda de la nueva ventana, con respecto al escritorio en el que se trabaje.
    glutInitWindowPosition(WINDOW_X, WINDOW_Y);
    //Comprobamos que el ancho y alto de nuestra ventana es menor que los pixeles de la pantalla.
    //En ese caso no cabria nuestra ventana en la pantalla
    if ( glutGet(GLUT_SCREEN_WIDTH) == 0 || glutGet(GLUT_SCREEN_WIDTH) < WIDTH)
        throw out_of_range("Error: El ancho no puede ser cero. Error ancho pantalla");
    if (glutGet(GLUT_SCREEN_HEIGHT) == 0 || glutGet(GLUT_SCREEN_HEIGHT) < HEIGHT)
        throw std::out_of_range("Error: El alto no puede ser cero. Error alto pantalla");
    //El ancho y alto de la nueva ventana.
    glutInitWindowSize(WIDTH,HEIGHT);
    // Esta función es la que propiamente crea la ventana y el parámetro es el nombre de la misma.
    glutCreateWindow("Random Maze");

              //Ghost g;
            //  g= new Ghost();
              int x= m.getRows();
              int y =m.getColumns();
             // playingGhosts.push_back(5,7);// Esto esta en mapa hay que traducirlo a pantalla o al reves...insertar en pantalla directamente
              /*g.set_positionMap((x/2) - 1, (y/2) -1); // Blinky
              playingGhosts.push_back(g);
              g.set_positionMap((x/2) - 1, (y/2)); // Pinky
              playingGhosts.push_back(g);
              g.set_positionMap((x/2), (y/2)-1); // Inky
              playingGhosts.push_back(g);
              g.set_positionMap((x/2),(y/2)); // Pokey
              playingGhosts.push_back(g);*/

              //cout << "Numero de fantasmas en vector: " << playingGhosts.size() << endl;
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutSpecialFunc(specialkeyboard);
    glutIdleFunc(idle);
    /*Especifica la matriz actual para realizar la composición. En ogl las operaciones de rotación, translación, escalado, etc. se
     * realizan a través de matrices de transformación. Dependiendo de lo que estemos tratando, hay tres tipos de matriz (que son
     * los tres posibles flags que puede llevar de parámetro la función): matriz de proyección (GL_PROJECTION),
     * matriz de modelo (GL_MODELVIEW) y matriz de textura (GL_TEXTURE). Con esta función indicamos a cual de estas tres deben
     * afectar las operaciones. Concretamente, GL_PROJECTION afecta a las vistas o perspectivas o proyecciones.
     */
    glMatrixMode(GL_PROJECTION);
              /*glOrtho() define una perspectiva ortonormal. Esto quiere decir que lo que se ves será una proyección paralela en uno de los
               * planos definidos por los ejes. Los parámetros sirven para delimitar el volumen de vista y son, por este orden:
               * x_mínima, x_máxima, y_mínima, y_máxima, z_mínima, z_máxima, (estos dos últimos no son coordenadas como los cuatro primeros,
               * son distancias desde el punto de vista, positivas hacia donde apunta y negativas hacia el lado contrario) considerando que,
               * por defecto, el punto de vista está en el origen de coordenadas mirando hacia el eje negativo de z, estos valores son
               * desplazamientos desde este punto. Con estos seis valores se define el volumen que incluirá los objetos que se proyecten.*/
              gluOrtho2D(0,WIDTH-1,0,HEIGHT-1);
              //Esta función cede el control del flujo del programa a GLUT que, a partir de estos "eventos", irá llamando a las funciones que han sido pasadas como callbacks.
              glutMainLoop();
              return 0;
}
//la función display() al ser pasada a glutDisplayFunc(), será llamada cada vez que haya que redibujar la ventana

void display()
{
    //int starti,startj;
    /*Con esto se define el color con el que se borrara el buffer al hacer un glClear().
     * Los 3 primeros parámetros son las componentes R, G y B, siguiendo un rango de [0..1]. La última es el valor alpha.
     */
    glClearColor(0.0,0.0,0.0,0.0);
    /* Borra un buffer o una combinación de varios. En este caso, borra el buffer de color (en realidad, cada componente
    R G y B tienen un buffer distinto, pero aquí los trata como el mismo), el que se pinta después en pantalla.
    Para borrarlos utiliza el color que ha sido previamente definido en init() mediante glClearColor(), en este caso,
    el (0,0,0,0) es decir, pinta todo el buffer de negro.*/
    glClear(GL_COLOR_BUFFER_BIT);
  m.drawMaze(WIDTH,HEIGHT);
  myPacman.draw();
  if(ghosts > 0)
  Blinky.draw(1.0,0.0,0.0);
  if(ghosts > 1)
  Pinky.draw(0.73,0.56,0.56);
  if(ghosts > 2)
  Inky.draw(0.0,1.0,1.0);
  if(ghosts > 3)
  Pokey.draw(1.0,0.5,0.0);
  //movimiento fantasmas, no sirve
  /*for(int i = 0; i < playingGhosts.size(); i++)
     {
      playingGhosts[i].draw();
      startj = playingGhosts[i].get_positionMapJ();
      starti = playingGhosts[i].get_positionMapI();
      cout << "Fantasma " << i << "Pos j: " << startj << endl;
      cout << "Fantasma " << i << "Pos i: " << starti << endl;
      m.moveGhost(starti,startj);

      startj = playingGhosts[i].get_positionMapJ();
          starti = playingGhosts[i].get_positionMapI();
          cout << "FantasmaPost " << i << "Pos j: " << startj << endl;
          cout << "FantasmaPost " << i << "Pos i: " << starti << endl;
     }*/


  //to-do comment
  glutSwapBuffers();
  //Le dice al procesador de eventos de GLUT que la ventana actual necesita ser redibujada
  //glutPostRedisplay();
}


/*-----------------------------------------------
//-----------------------------------------------
void display()
{
  glClearColor(0,0,0,0.0);
  glClear(GL_COLOR_BUFFER_BIT);
  myPacman.draw();
  glutSwapBuffers();
}
*/
//-----------------------------------------------
//-----------------------------------------------
void keyboard(unsigned char c,int x,int y)
{
  Ghost glocal;
  switch(c)
    {
    case 27: // ESC
          exit (0);
          break;
    case 43: // key '+' to add a ghost  //could be 65 (a) o 97(A)
        // Siempre insertamos en el mismo sitio, podemos mirar de cambiar el sitio. Nota posicion x e y en mapa.
        ghosts++;
         glocal.set_positionMap((x/2) - 1, (y/2) -1);
         playingGhosts.push_back(glocal);
         cout << "Añadimos fantasma. Numero de fantasmas en vector: " << playingGhosts.size() << endl;
         break;
    case 45: // key '-' to remove a ghost  //could be 81 (q) o 113 (Q)
            //Nos aseguramos de que siempre haya al menos un fantasma jugando
        if (ghosts > 1) ghosts--;
             if (playingGhosts.size() > 1) {
                 playingGhosts.pop_back();
                 cout << "Eliminamos fantasma. Numero de fantasmas en vector: " << playingGhosts.size() << endl;
             }
             else cout << "No podemos eliminar fantasma. Al menos tiene que haber un fantasma en juego.Numero de fantasmas en vector: " << playingGhosts.size() << endl;
            // playingGhosts.pop_back();
            break;
   }
  glutPostRedisplay();
}
void specialkeyboard(int key,int x,int y)
{
    /*
if ( myPacman.getState() == QUIET) // Creo que necesario si avanzamos d muchos en muchos...
{*/
    switch(key)
    {
    case GLUT_KEY_UP:
            goNorth();
            break;
    case GLUT_KEY_DOWN:
            goSouth();
            break;
    case GLUT_KEY_LEFT:
             myPacman.moveWest(m, s);
            //goWest();
            break;
    case GLUT_KEY_RIGHT:
            myPacman.moveEast(m, s);
            cout << "Maze esta bien: " << m.getRows() << endl;
            //goEast();
            break;
            //Falta igual un default
    //}
}
    //glutPostRedisplay();
  glutPostRedisplay();
}

我的pacman类实现:

#include "Pacman.h"


namespace RandomMaze {
Pacman::Pacman() {
    // TODO Auto-generated constructor stub
}
Pacman::~Pacman() {
    // TODO Auto-generated destructor stub
}
//-----------------------------------------------
void Pacman::moveEast(Maze m, Screen s)
{
                    int starti,startj, endi, endj;
                    int relacionAncho=int(s.getWidth() / m.getColumns());
                    int relacionAlto= int(s.getHeigth() / m.getRows());
                    int ysim;
                    cout << "relacionAnchoDentro : " << relacionAncho << endl;
                    cout << "relacionAltoDentro :  " << relacionAlto << endl;
                    starti = m.getPacmanX();
                    startj = m.getPacmanY();
                    cout << "Pacman posicion inicial i D: " << starti << endl;
                    cout << "Pacman posicion inicial j D: " << startj << endl;
                    ysim=0;
                    ysim=m.getRows();
                    cout << "PacmanX numero rows D: " << ysim << endl;
                    ysim= ysim-starti;
                    cout << "PacmanX ysim resultante: D" << ysim << endl;
                    set_positionScreen(startj*relacionAncho,ysim*relacionAlto);
                    cout << "Set positicion Screen Ancho D: " << startj*relacionAncho << " Alto: D" << ysim*relacionAlto << endl;
                    if ( m.isPassageOrFood( starti, startj+1)) // Si el map de arriba es visitable
                                { //actualizo posicion de pacman
                                m.deleteFood(starti,startj);
                                m.setPacman(starti,startj+1); // NO FOOD PORQUE YA HE PASADO
                                //myPacman.set_positionScreen(startj*relacionAncho,starti*relacionAlto);//  map[x][y-1]=PACMAN; //El sitio de arriba es pacman
                                    //myPacman.init_movement(x,y-1, 1000);
                                //m.drawMaze(WIDTH,HEIGHT);
                                startj++;
                                }

                    //colocacion pacman
                    /** Aqui hay algo mal calculado
                                         * La posiciones iniciales van al reves y no estan bien calculadaslo que va tan rapido que no lo vemos
                                         * el set position aqui no hace falta**/
                    /** PACMAN vota, seguro q hay alguna doble inicializacion de la posicion inicial */
                    endi=starti;
                                endj=startj;
                                cout << "Posicion final i: D" << endi << endl;
                                cout << "Posicion final j: D" << endj << endl;
                            //  set_positionScreen(startj*relacionAncho,ysim*relacionAlto);
                            //  cout << "Me voy a mover desde x: D" << startj*relacionAncho << endl;
                            //  cout << "Me voy a mover desde y: D" << starti*relacionAlto << endl;
                            //  ysim=m.getRows()-endi;
                                //myPacman.set_position(y*relacionAncho,ysim*relacionAlto);PACMAN_SPEED
                                init_movement(endj*relacionAncho,ysim*relacionAlto, 100); //RATIO hace votar a PACMAN
                                cout << "Me voy a mover hasta x: D" << endj*relacionAncho << endl;
                                cout << "Me voy a mover hasta y: D" << ysim*relacionAlto << endl;
}

//-----------------------------------------------
void Pacman::moveWest(Maze m, Screen s)
{
                    int starti,startj, endi, endj;
                    int relacionAncho=int(s.getWidth() / m.getColumns());
                    int relacionAlto= int(s.getHeigth() / m.getRows());
                    int ysim;
                    cout << "relacionAnchoDentro : " << relacionAncho << endl;
                    cout << "relacionAltoDentro :  " << relacionAlto << endl;
                    starti = m.getPacmanX();
                    startj = m.getPacmanY();
                    cout << "Pacman posicion inicial i D: " << starti << endl;
                    cout << "Pacman posicion inicial j D: " << startj << endl;
                    ysim=0;
                    ysim=m.getRows();
                    cout << "PacmanX numero rows D: " << ysim << endl;
                    ysim= ysim-starti;
                    cout << "PacmanX ysim resultante: D" << ysim << endl;
                    set_positionScreen(startj*relacionAncho,ysim*relacionAlto);
                    cout << "Set positicion Screen Ancho D: " << startj*relacionAncho << " Alto: D" << ysim*relacionAlto << endl;
                    if ( m.isPassageOrFood( starti, startj-1)) // Si el map de arriba es visitable
                                                        { //actualizo posicion de pacman
                                                        m.deleteFood(starti,startj);
                                                        m.setPacman(starti,startj-1); // NO FOOD PORQUE YA HE PASADO
                                                        //  map[x][y-1]=PACMAN; //El sitio de arriba es pacman
                                                            //myPacman.init_movement(x,y-1, 1000);
                                                        //myPacman.set_positionScreen(startj*relacionAncho,starti*relacionAlto);
                                                        //m.drawMaze(WIDTH,HEIGHT);
                                                        startj--;
                                                        }
                    //colocacion pacman
                    /** Aqui hay algo mal calculado
                                         * La posiciones iniciales van al reves y no estan bien calculadaslo que va tan rapido que no lo vemos
                                         * el set position aqui no hace falta**/
                    /** PACMAN vota, seguro q hay alguna doble inicializacion de la posicion inicial */
                    endi=starti;
                                endj=startj;
                                cout << "Posicion final i: D" << endi << endl;
                                cout << "Posicion final j: D" << endj << endl;
                            //  set_positionScreen(startj*relacionAncho,ysim*relacionAlto);
                            //  cout << "Me voy a mover desde x: D" << startj*relacionAncho << endl;
                            //  cout << "Me voy a mover desde y: D" << starti*relacionAlto << endl;
                            //  ysim=m.getRows()-endi;
                                //myPacman.set_position(y*relacionAncho,ysim*relacionAlto);PACMAN_SPEED
                                init_movement(endj*relacionAncho,ysim*relacionAlto, 100); //RATIO hace votar a PACMAN
                                cout << "Me voy a mover hasta x: D" << endj*relacionAncho << endl;
                                cout << "Me voy a mover hasta y: D" << ysim*relacionAlto << endl;
}
void Pacman::draw()
{
   glColor3f(1.0,1.0,0.0);
  //Draw Circle
            glBegin(GL_POLYGON);
                //Change the 6 to 12 to increase the steps (number of drawn points) for a smoother circle
                //Note that anything above 24 will have little affect on the circles appearance
                //Play with the numbers till you find the result you are looking for
                //Value 1.5 - Draws Triangle
                //Value 2 - Draws Square
                //Value 3 - Draws Hexagon
                //Value 4 - Draws Octagon
                //Value 5 - Draws Decagon
                //Notice the correlation between the value and the number of sides
                //The number of sides is always twice the value given this range
                for(double i = 0; i < 2 * PI; i += PI / 6) //<-- Change this Value
                    glVertex3f(cos(i) * RADIUS + x+7.5, sin(i) * RADIUS + y-10, 0.0);
            glEnd();
            //Draw Circle
}
void Pacman::drawPacman()
{
  glColor3f(1,1,1);
  glBegin(GL_QUADS);
  glVertex2i(x-6,y-6);
  glVertex2i(x+6,y-6);
  glVertex2i(x+6,y+6);
  glVertex2i(x-6,y+6);
  glEnd();
}
} /* namespace RandomMaze */

因此,基本想法是:如果我想向西(左箭头),我会查看地图:如果可以(是通道或食物),那么我会更新mypacman在地图中的位置(使用m.setPacman(i,j)),并计算屏幕坐标和这些坐标的init_movement(pacman是从粒子继承的类)。

void particle::init_movement(int destination_x,int destination_y,int duration)
{
  vx = (destination_x - x)/duration;
  vy = (destination_y - y)/duration;
  state=MOVE;
  time_remaining=duration;
}

当我第一次向东移动时,屏幕变黑,第二次出现错误:"/home/eduardo/Desarrollo/adttrabajos/RandomMase/Debug/RandomMase"中出错:free():无效指针:0x00007f40dd418db8***

MoveWest 也是如此

我想,当我在操作中更新位置或改变迷宫时,某种免费的东西在我不知情的情况下启动了。

感谢

pd:mazze.h

#define WALL 0
#define PASSAGE 1
#define FOOD 2
#define VISITED 9
#define RATIO 0.4
//Personajes
#define PACMAN 10 //Comecocos, amarillo
#define BLINKY 11  //Fantasma Rojo ( cazador)
#define PINKY 12  //Fantasma Rosa( emboscador)
#define INKY  13 //Fantasma Azul, cian ( caprichoso)
#define POKEY  14  //Fantasma Naranja ( bobo)


namespace RandomMaze {
/** Esta clase genera y gestiona el laberinto del juego. */
class Maze {
    private:
        int previousBlinky = BLINKY;
        int previousPinky = PINKY;
        int previousInky = INKY;
        int previousPokey = POKEY;
        //Atributos publicos
    public:
        int **map;
        int rows, columns;
        int level;
    //Metodos privados
    private:
        void fillMaze();
        void addBorders();
        void centerWalls();
        void addWalls();
        void exploreMaze(int fila, int columna);
        void checkWalls(int fila, int columna);
        void checkWalls();
        bool isConnected();
        bool isCenter(int r, int c);
        void getaway();
        int isWall(int level);
        void deleteBrick(int i, int j);
        void addFood();
        void addPacman();
        void addBlinky();
        void addPinky();
        void addInky();
        void addPokey();
    //Metodos públicos
    public:
        Maze();
        ~Maze(void);
        Maze(int filas, int columnas, int level);
        double getN();
        void setupMaze(int filas, int columnas, int level);
        void moveGhost(int fila, int columna);
        void printMaze();
        void setRows(int filas);
        void setColumns(int columnas);
        void setLevel(int nivel);
        int getRows();
        int getColumns();
        int getLevel();
        int** getMaze();
        // Pacman
        int getPacmanX();
        int getPacmanY();
        void setPacman( int x,int j);
        //Blinky
        int getBlinkyX();
        int getBlinkyY();
        void setBlinky( int x,int j);
        void setPreviousBlinky(int x,int j);
        //Pinky
        int getPinkyX();
        int getPinkyY();
        void setPinky( int x,int j);
        void setPreviousPinky(int x,int j);
        //INKY
        int getInkyX();
        int getInkyY();
        void setInky( int x,int j);
        void setPreviousInky(int x,int j);
        //POKEY
        int getPokeyX();
        int getPokeyY();
        void setPokey( int x,int j);
        void setPreviousPokey(int x,int j);
        void drawMaze(int width, int height);
        bool isPassageOrFood( int x, int y);
        void deleteFood(int x,int y);
};

} /* namespace RandomMaze */
void Pacman::moveWest(Maze m, Screen s)

这是你的问题。

调用此函数时,会调用MazeScreen的复制构造函数。函数返回后,将对创建的对象调用析构函数。默认的自动生成的复制构造函数将简单地将所有成员复制到新对象(包括int**映射指针。然后,当它被破坏时,该指针将被释放,但原始迷宫仍然保留对该指针的引用,下次调用该函数时,将发生双自由错误。

你想要的是将一个引用或指针传递给迷宫(可能还有屏幕):

void Pacman::moveWest(Maze* m, Screen* s)

为了避免这样的错误,您至少应该声明复制构造函数和赋值运算符。这意味着遵循3的规则,即如果一个类有析构函数,它也应该有一个复制构造函数和一个赋值运算符。还有一条规则是5,它说你也需要移动变体。