2 votes

Code::Blocks crashea con process returned 0xC0000005

I am making a game in C++ that consists of a Pokémon battle between three pokémon (Pikachu, Charmander and Squirtle). When I give it play, it appears Ataca Pikachu and then the "Pokémon.exe stopped working" banner appears. I leave the code of the main and classes Pokémons.h y Pikachu.h . Any help is welcome. Thank you.

main.cpp

#include <iostream>
#include <cstdlib>
#include <list>
#include "Pokemons.h"
#include "Pikachu.h"
#include "Charmander.h"
#include "Squirtle.h"

using namespace std;

int main()
{
    Pokemons *pokemon;
    Pikachu  *pikachu = new Pikachu();
    Charmander *charmander = new Charmander();
    Squirtle *squirtle = new Squirtle();

    cout << pikachu->getNombre() << endl;
    cout << pikachu->getVida() << endl;
    cout << pikachu->getAtaque() << endl;
    cout << "\n" << endl;
    cout << charmander->getNombre() << endl;
    cout << charmander->getVida() << endl;
    cout << charmander->getAtaque() << endl;
    cout << "\n" << endl;
    cout << squirtle->getNombre() << endl;
    cout << squirtle->getVida() << endl;
    cout << squirtle->getAtaque() << endl;
    system("CLS");
    list<Pokemons*>* listaPokemons = new list<Pokemons*>;
    listaPokemons->push_back(pikachu);
    listaPokemons->push_back(charmander);
    listaPokemons->push_back(squirtle);
    Pokemons* objetivo;
    list<Pokemons*>::iterator pos;
    pos = listaPokemons->begin();

    while(objetivo->getVida() > 0)
    {
        cout << "Ataca " << (*pos)->getNombre() << endl;
        cout << "El pokemon " << objetivo->getNombre() << " recibe un ataque de " << (*pos)->atacar(objetivo) << " puntos" << endl;
        cout << "La vida de " << objetivo->getNombre() << " queda en " << objetivo->getVida() << " puntos" << endl;
        cout << endl;
        cout << "Ataca " << (*pos)->getNombre() << endl;
        cout << "El pokemon " << objetivo->getNombre() << " recibe un ataque de " << (*pos)->atacar(objetivo) << " puntos" << endl;
        cout << "La vida de " << objetivo->getNombre() << " queda en " << objetivo->getVida() << " puntos" << endl;
        cout << endl;
        pos++;

        if(pos == listaPokemons->end())
        {
            pos = listaPokemons->begin();
        }
    }

    delete objetivo;
    pos = listaPokemons->begin();

    while(pos != listaPokemons->end())
    {
        delete (*pos);
        pos++;
    }

    delete listaPokemons;
    return 0;
}

Pokémons.h

    #ifndef POKEMONS_H_INCLUDED
    #define POKEMONS_H_INCLUDED

    #include <string>

    class Pokemons
    {
    protected:
        std::string nombre;
        int vida;
        int ataque;

    public:
        std::string getNombre();
        int getVida();
        int getAtaque();
        virtual void recibirDanio(int) = 0;
        virtual ~Pokemons(){ };
        virtual int atacar(Pokemons* objetivo) = 0;
    };

    std::string Pokemons::getNombre()
    {
        return this->nombre;
    }

    int Pokemons::getVida()
    {
        return this->vida;
    }

    int Pokemons::getAtaque()
    {
        return this->ataque;
    }

    #endif // POKEMONS_H_INCLUDED

Pikachu.h

#ifndef PIKACHU_H_INCLUDED
#define PIKACHU_H_INCLUDED

#include <string>

class Pikachu: public Pokemons
{

public:

    Pikachu() {
        this->nombre = "Pikachu";
        this->vida = 100;
        this->ataque = 50;
    }

    void recibirDanio(int danio){
        this->vida -= danio/2;
    }

    virtual int atacar(Pokemons* target) {
        target->recibirDanio(this->ataque);
    }
};

#endif // PIKACHU_H_INCLUDED

NOTE 1: The code of the other two pokémon is identical since the three classes inherit from the parent class Pokémones.h .

NOTE 2: I did a debug and it tells me that the problem is in lines 41 ( main ) y 22 ( Pikachu.h ),

0 votes

This Pokémon game is superior to the Sword/Shield game. This one at least brings Squirtle.

4voto

PaperBirdMaster Points 24910

When I press play, the following appears Ataca Pikachu and then the "Pokémon.exe stopped working" banner appears.

The surprising thing is that it even shows you a message because the instruction before your first message is already wrong:

Pokemons* objetivo;            // 'objetivo' está vacío
list<Pokemons*>::iterator pos; // 'pos' está vacío
pos = listaPokemons->begin();  // 'pos' apunta al primer elemento de 'listaPokemons' ('pikachu')

while(objetivo->getVida() > 0) // objetivo SIGUE VACÍO pero pides algo de su interior, debería fallar.
{
    cout << "Ataca " << (*pos)->getNombre() << endl;

The error 0xC0000005 corresponds to an invalid use of memory, specifically to uninitialized memory an error to which your code is very prone because you use raw pointers without any need to do so. I propose you some changes:

Proposal.

// No uses el plural cuando te refieres a objetos.
class Pokemon
{
protected:
    // Inicializa los miembros como vacíos
    std::string nombre{};
    int vida{};
    int ataque{};

public:
    // Usa un constructor para asignar valores internos.
    Pokemon(std::string Nombre, int Vida, int Ataque) :
        nombre{Nombre}, vida{Vida}, ataque{Ataque}
    {}
    // La función no modifica el objeto: debe ser 'const'.
    // Puedes devolver una referencia constante al nombre, evitando copias de datos innecesarias.
    // Ya sabemos que estas leyendo el nombre, el 'get' es redundante (y mezcla idiomas).
    const std::string &Nombre() const
    {
        // No hay ningún otro 'nombre' aquí, el 'this->' es innecesario.
        return nombre;
    }
    // La función no modifica el objeto: debe ser 'const'.
    // Ya sabemos que estas leyendo la vida, el 'get' es redundante (y mezcla idiomas).
    int Vida() const
    {
        // No hay otra 'vida' aquí, el 'this->' es innecesario.
        return vida;
    }
    // La función no modifica el objeto: debe ser 'const'.
    // Ya sabemos que estas leyendo el ataque, el 'get' es redundante (y mezcla idiomas).
    int Ataque() const
    {
        // No hay otro 'ataque' aquí, el 'this->' es innecesario.
        return vida;
    }
    virtual void recibirDanio(int) = 0;
    // Si el cuerpo del destructor va a estar vacío, deja que el compilador se ocupe.
    virtual ~Pokemon() = default;
    // Evita los punteros, usa referencias.
    virtual void atacar(Pokemon& objetivo) = 0;
};

// Si todos los miembros van a ser públicos, valora usar una struct
struct Pikachu: public Pokemon
{
    // Llama al constructor de la clase base
    Pikachu() : Pokemon{"Pikachu", 100, 50}
    {}

    void recibirDanio(int danio) {
        // No hay otra 'vida' aquí, el 'this->' es innecesario.
        vida -= danio/2;
    }

    // No pretendes sobrecargar más esta función, el 'virtual' es innecesario.
    // Pretendes sobrecargar la función base, no olvides el 'override'
    // Evita los punteros, usa referencias.
    // No devuelves ningún valor, la función debería ser 'void'.
    void atacar(Pokemon& target) override {
        // No hay otro 'ataque' aquí, el 'this->' es innecesario.
        target.recibirDanio(ataque);
    }
};

int main()
{
    // No necesitas memoria dinámica para crear la lista.
    // Puedes crear los Pokémon al mismo tiempo que la lista
    list<Pokemon*> listaPokemons
    {
        new Pikachu, new Charmander, new Squirtle
    };

    // Puedes listar con bucles lo que tienes en la lista, en lugar de uno a uno
    for (const auto &pokemon : listaPokemons)
    {
        // Un solo 'cout' es suficiente
        cout << pokemon->Nombre() << '\n'
             << pokemon->Vida() << '\n'
             << pokemon->Ataque() << '\n'
             // Si solo imprimes un carácter, no uses un literal de cadena.
             // un 'endl' por llamada es suficiente.
             << '\n' << endl;
    }

    // … hacer cosas    

    // Puedes borrar el contenido de la lista con otro sencillo bucle:
    for (const auto &pokemon : listaPokemons)
        delete pokemon;    

    return 0;
}

0 votes

I tried your proposal and I get the following errors conflicting return type specified for 'virtual void Pikachu::Atacar(Pokemon&)' y overriding 'virtual int Pokemon::Atacar(Pokemon&)' .

1 votes

That's because I got confused when writing the proposal: both the base function and the derivative must have the same return type. That is the grace to use override which warns you if you are not overwriting the function properly.

0 votes

In the for which lists the contents of listaPokemons I get the error expected primary-expression before '->' token in the cout .

3voto

The problem I see in code is that you declare a pointer but never initialize it. The code is as follows:

    Pokemons* objetivo;

Note that the above statement does not initialize the variable, therefore, it will take an object as address Pokemons at its current value.

Later you use this variable in the while :

    list<Pokemons*>::iterator pos;
    pos = listaPokemons->begin();

    while(objetivo->getVida() > 0)

When you don't initialize a pointer it has any memory address, so wherever it points to it will try to invoke getVida() using the offset to this function, but since it is bool perhaps it will enter the while but I don't think I'll get out of this one alive. Anything can happen there, even the team can be knocked down.

Whenever you use pointers, initialize them to NULL, because this way the error will be due to a null pointer. Working with pointers in c++ is very risky. I would recommend you to use the Smart pointers of the STL.

To tell you the truth, I don't know much about Pokemon so I couldn't tell you what object I should be aiming at.

HolaDevs.com

HolaDevs is an online community of programmers and software lovers.
You can check other people responses or create a new question if you don't find a solution

Powered by:

X