类对象数组出现问题会导致崩溃

时间:2018-10-26 21:40:34

标签: c++

所以我正在制作一个基于文本的RPG,我想一次遇到多个敌人。因此,我修改了确定是否将Monster类的对象填充到Monster类数组中并将对象bool设置为true的函数,如您在此处看到的那样:

Monster * Map::checkRandomEncounter()
{

    Monster* monster = new Monster[3];

    for (int i = 0; i < 3; i++)
    {

        int roll = Random(0, 20);
        if (roll <= 5)
        {
//No encounter
            return 0;
        }

        else if (roll > 6 && roll < 10)
        {
            monster[i] = Monster();
            monster[i].giveID("Orc", 10, 8, 200, 100, 1, "Short Sword", 2, 7);

            monster[i].isFilled();
            std::cout << "You encounter an Orc!" << std::endl;
            std::cout << "Prepare for battle!" << std::endl;
            std::cout << std::endl;
        }
        else if (roll >= 11 && roll <= 15)
        {
            monster[i] = Monster();
            monster[i].giveID("Goblin", 6, 6, 100, 75, 0, "Dagger", 1, 5);

            monster[i].isFilled();
            std::cout << "You encounter a Goblin!" << std::endl;
            std::cout << "Prepare for battle!" << std::endl;
            std::cout << std::endl;
        }
        else if (roll >= 16 && roll <= 19)
        {
            monster[i] = Monster();
            monster[i].giveID("Ogre", 20, 12, 500, 200, 2, "Club", 3, 8);
            monster[i].isFilled();

            std::cout << "You encounter an Ogre!" << std::endl;
            std::cout << "Prepare for battle!" << std::endl;
            std::cout << std::endl;
        }
        else if (roll == 20)
        {
            monster[i] = Monster();
            monster[i].giveID("Orc Lord",
                              25,
                              15,
                              2000,
                              1000,
                              5,
                              "Two Handed Sword",
                              5,
                              20);
            monster[i].isFilled();

            std::cout << "You encounter an Orc Lord!" << std::endl;
            std::cout << "Prepare for battle!" << std::endl;
            std::cout << std::endl;
        }
    }
    return monster;
}

上面的函数将在我的主函数中调用,如下所示:

int main()
{
    srand(time(0));
    Map gameMap;

    Player mainPlayer;
    mainPlayer.createClass();

    //Beginn adventure
    bool done = false;
    while (done == false)
    {
        // Each Loop Cycle outputs player pos and selection menu
        gameMap.printPlayerPos();

        int selection = 1;
        std::cout << "1) Move 2) Rest 3) View Stats 4) Quit: ";
        std::cin >> selection;

        Monster* monster = 0;
        switch (selection)
        {
            case 1: // Move the player
                gameMap.movePlayer();

                if (gameMap.getPlayerXPos() == 2
                        && gameMap.getPlayerYPos() == 3)
                {
                    std::cout << "You see a store nearby !" << std::endl;
                }

                if (gameMap.getPlayerXPos() == 2
                        && gameMap.getPlayerYPos() == 4)
                {
                    Store store;
                    store.enter();
                    store.showInventory(mainPlayer);
                }

                //Check for a random encounter
                //returns a null pointer if no encounter happened
                monster = gameMap.checkRandomEncounter();

                //'monster' not null, start battle script
                if (monster != 0)
                {
                    //Loop until a break statement
                    for (int i = 0; i < 3; i++)
                    {
                        //Display Hitpoints
                        mainPlayer.displayHitPoints();
                        monster[i].displayHitPoints();
                        std::cout << std::endl;

                        //Players turn to attack first
                        **bool runAway = mainPlayer.attack(monster, mainPlayer);** // Crash happening in this area

                        if (runAway) // Player flees
                        {
                            break;
                        }
                        if (monster[i].isDead())
                        {
                            mainPlayer.victory(monster->getXPReward(),
                                               monster->getGoldReward());
                            mainPlayer.levelUp(mainPlayer);

                        }
                        break;

                        //Monster attacks
                        monster[i].attack(mainPlayer);

                        if (mainPlayer.isDead())
                        {
                            mainPlayer.gameOver();
                            done = true;
                            break;
                        }
                    }

                    //Pointer to Monster must destroy created instance of Monster
                    //to make sure that there is no Memory leak

                }
                delete monster;
                monster = 0;

                break;
            case 2: // resting
                mainPlayer.rest();
                monster = gameMap.checkRandomEncounter();

                //'monster' not null, start battle script
                monster = gameMap.checkRandomEncounter();

                //'monster' not null, start battle script
                if (monster != 0)
                {
                    //Loop until a break statement
                    for (int i = 0; i < 3; i++)
                    {
                        //Display Hitpoints
                        mainPlayer.displayHitPoints();
                        monster[i].displayHitPoints();
                        std::cout << std::endl;

                        //Players turn to attack first
                        bool runAway = mainPlayer.attack(monster, mainPlayer);

                        if (runAway) // Player flees
                        {
                            break;
                        }
                        if (monster[i].isDead())
                        {
                            mainPlayer.victory(monster->getXPReward(),
                                               monster->getGoldReward());
                            mainPlayer.levelUp(mainPlayer);

                        }
                        break;

                        //Monster attacks
                        monster[i].attack(mainPlayer);

                        if (mainPlayer.isDead())
                        {
                            mainPlayer.gameOver();
                            done = true;
                            break;
                        }
                    }

                    //Pointer to Monster must destroy created instance of Monster
                    //to make sure that there is no Memory leak

                }
                delete monster;
                monster = 0;

                break;
            case 3: // viewing stats
                mainPlayer.viewStats();
                break;
            case 4: // quitting
                done = true;
                break;
        }
    }

    return 0;
}

最后是拼图,这是玩家攻击怪物的功能:

bool Player::attack(Monster Monster[], Player& Player)
{
    int ArmorBefore = 0;

    int Roll = 0;
    int selection = 1;
    int i;

    if (Monster[0].isFilled() == true)
    {
        i = 0;
    }
    else if (Monster[1].isFilled() == true)
    {
        i = 1;
    }
    else if (Monster[2].isFilled() == true)
    {
        i = 2;
    }

    if (Monster[i].isFilled() == true)
    {

        std::cout << "1) Attack 2) Run 3) Cast Spell 4) Use Item: ";
        std::cin >> selection;
        std::cout << std::endl;

        switch (selection)
        {
            case 1: // Player fights
                std::cout << " You attack an " << Monster[i].getName()
                        << " with a " << mWeapon.mName << std::endl;

                if (Random(0, 20) < mAccuracy) // Player hits Monster
                {
                    int damage = Random(mWeapon.mDamageRange);
                    int totalDamage = damage - Monster[i].getArmor();

                    if (totalDamage <= 0) // Armor is equal or higher than player atk
                    {
                        std::cout << "Your attack failed to penetrate "
                                << Monster[i].getName() << "'s armor !"
                                << std::endl;
                        return false;
                    }
                    else // Attack is higher than Monsters armor
                    {
                        std::cout << "You hit " << Monster[i].getName()
                                << " for " << totalDamage << " damage !"
                                << std::endl;
                        // Subtract dmg from Monsters hp
                        Monster[i].takeDamage(totalDamage);
                        return false;
                    }
                }
                else // Player Misses
                {
                    std::cout << "You miss !" << std::endl;
                }
                std::cout << std::endl;
                return false;
                break;
            case 2: // Player runs with a 25% chance
                Roll = Random(1, 4);

                if (Roll == 1) // Success
                {
                    std::cout << "You run away !" << std::endl;
                    return true; // <- Return out of the function
                }
                else
                {
                    std::cout << "You failed to escape !" << std::endl;
                    return false;
                }
            case 3: // Casting Spell
            {
                int SpellSelect;
                // Spells for the Fighter
                if (Player.mClassName == "Fighter")
                {

                    std::cout << std::endl;
                    std::cout << "1) Shield 2) Mighty Blow: ";
                    std::cin >> SpellSelect;
                    if (SpellSelect == 1)
                    {
                        if (Player.mMagicPoints >= 10) // checks for player mana
                        {
                            std::cout << "You cast a mighty shield!"
                                    << std::endl;
                            ArmorBefore = Player.mArmor;
                            Player.shield(Player);
                            Player.mMagicPoints -= 10;

                        }
                        else
                        {
                            std::cout << "Not enough Mana" << std::endl;
                            break;
                        }
                    }
                    else
                    {
                        if (Player.mMagicPoints >= 5) // casting Mighty Blow
                        {
                            int damage = Random(mMightyBlow.mDamageRange);
                            std::cout
                                    << "You strike with all your might ! and Deal "
                                    << damage << " damage !" << std::endl;
                            Monster[i].takeDamage(damage);
                            Player.mMagicPoints -= 5;
                            return false;
                        }
                        else
                        {
                            std::cout << "Not enough Mana" << std::endl;
                            return false;
                        }
                    }

                }
                //Spells for the Wizard
                else if (Player.mClassName == "Wizard")
                {
                    std::cout << "1) Fireball";
                    std::cin >> SpellSelect;

                    if (Player.mMagicPoints >= 45)
                    {
                        int damage = Random(mFireball.mDamageRange);
                        std::cout << "You cast a Fireball and deal " << damage
                                << " damage !" << std::endl;
                        Monster[i].takeDamage(damage);
                        Player.mMagicPoints -= 45;
                        return false;
                    }
                    else
                    {
                        std::cout << "Not enough Mana" << std::endl;
                        return false;
                    }

                }
                // Spells for the Cleric
                else if (Player.mClassName == "Cleric")
                {
                    std::cout << "1) Magic Missile";
                    std::cin >> SpellSelect;

                    if (Player.mMagicPoints >= 35)
                    {
                        int damage = Random(mMagicMissile.mDamageRange);
                        std::cout << "You cast a Magic Missile and deal "
                                << damage << " damage !" << std::endl;
                        Monster[i].takeDamage(damage);
                        Player.mMagicPoints -= 35;
                    }
                    else
                    {
                        std::cout << "Not enough Mana" << std::endl;
                        return false;
                    }

                }

            }
            case 4: // using Item
                int invSlot;
                std::cout << "1) HP Potion: ";
                std::cin >> invSlot;

                if (invSlot == 1) // Potion slot
                {
                    if (mHPot.mAmount.size() > 0)
                    {
                        std::cout << "You used a Potion and healed for 5 HP !"
                                << std::endl;
                        int currentSize = mHPot.mAmount.size();
                        mHPot.mAmount.resize(currentSize - 1);
                        Player.mHitPoints += 5;
                        if (Player.mHitPoints > Player.mMaxHitPoints)
                        {
                            Player.mHitPoints = Player.mMaxHitPoints;
                        }
                        return false;
                    }
                    else
                    {
                        std::cout << "You have no Potions!" << std::endl;
                        return false;
                    }

                }
                else // wrong slot
                {
                    std::cout << "No Item found!" << std::endl;
                    return false;
                }

        }
        // Clearing stat boosts
        if (Player.shield(Player) == true)
        {
            Player.mArmor = ArmorBefore;
        }
    }

    return false;
}

当我运行游戏时,有时会遇到问题,即在阵列的插槽中填充怪物后,将不会触发任何战斗。而且如果要打一场战斗,我每次都会崩溃,并显示错误报告,内容为:

_CrtlValidHeadPointer(block)

我想我的指针不能正常工作...。但是由于我是初学者,所以我几乎陷于困境。我非常感谢您的启发:)

1 个答案:

答案 0 :(得分:3)

这个地方可能会引起未定义的行为并崩溃:

int i;

if (Monster[0].isFilled() == true)
{
    i = 0;
}
else if (Monster[1].isFilled() == true)
{
    i = 1;
}   
else if (Monster[2].isFilled() == true)
{
    i = 2;
}
/*else // one of solutions
 break;*/

//"i" can be unset! and can have any value from INT_MIN to INT_MAX!

    if (Monster[i].isFilled() == true) //potentially index over array
    {

此外,内存管理还存在内存泄漏和未定义的行为:

Monster* monster = new Monster[3];
...
delete monster

必须为delete [] monster

但是建议使用智能指针,向量,数组等进行内存管理