引发异常:读取访问冲突[C ++]

时间:2018-07-09 06:21:56

标签: c++

嗨。我目前正在学习编程,因此暂时不清理代码,我需要帮助来使代码首先运行。另外,我对大量的代码块表示歉意。我不知道这是否与问题无关,所以我还是将所有问题都张贴了。

我们当前的课程是在课堂上,我正在尝试让2个向导互相对决。但是在此之前,我需要为任一向导的属性分配值:

class Spell
{
public:
    string name;
    unsigned int cost;
    unsigned int dmg;
};

class Wizard
{
public:
    string name;
    unsigned int hp;
    unsigned int mp;
    Spell* spell;
};


void assignWizardValues(Wizard* wizard, Spell* spell)
{
    wizard->hp = rand() % 25 + 76;
    wizard->mp = rand() % 25 + 76;
    spell->name = "Fireball";
    spell->cost = rand() % 10 + 6;
    spell->dmg = rand() % 10 + 6;
}

在我的main()中,我有这个:

int main()
{
    Wizard* wiz1 = new Wizard();
    Wizard* wiz2 = new Wizard();
    Spell* fireball1 = new Spell();
    Spell* fireball2 = new Spell();

    //Assign Property Values
    srand(time(NULL)); 

    cout << "Who is the first wizard?  ";
    cin >> wiz1->name;
    assignWizardValues(wiz1, fireball1);

    cout << "Who is the second Wizard?  ";
    cin >> wiz2->name;
    assignWizardValues(wiz2, fireball2);

    //Battle START!!

    while (canGoOn(wiz1) == true && canGoOn(wiz2) == true)
    {
        castSpell(wiz1, wiz2);
        castSpell(wiz2, wiz1);
    }

    system("pause");
    return 0;
}

为两个向导和两个咒语分配值都可以。然后,当它进入战斗循环时,就会弹出此错误:

Exception thrown: read access violation.
std::_String_alloc<std::_String_base_types<char,std::allocator<char> > 
>::_Get_data(...) returned nullptr.

这是我目前遇到的问题。 作为参考,这是我在该循环中可以使用的其他两个函数:

void castSpell(Wizard* caster, Wizard* enemy)
{
    cout << caster->spell->name << endl;
    caster->mp -= caster->spell->cost;
    enemy->hp -= caster->spell->dmg;
    cout << caster->hp << endl << caster->mp << endl << endl;
    cout << enemy->hp << endl << enemy->mp << endl << endl;
    cout << endl << endl;
}

bool canGoOn(Wizard* wizard)
{
    if (wizard->hp > 0 && wizard->mp > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

任何帮助将不胜感激,再次,我对代码转储感到抱歉,对不起代码不好,对不起,这篇文章太长了。我在绳子的尽头Tbh T ^ T

2 个答案:

答案 0 :(得分:0)

导致崩溃的问题是您没有在任何地方将魔术分配给向导,因此指针默认初始化为空指针。现在,您可以在castSpell函数中取消引用此空指针,以尝试访问无效的内存(未定义的行为)。

Best已经在构造函数中分配了该拼写,因此您永远不会陷入具有无效值的情况。您可以通过多种方式来做到这一点:

Wizard(std::string name)
    : name(std::move(name)), // std::move: avoids unnecessary copying of data...
      hp(rand() % 25 + 76),
      mp(rand() % 25 + 76),
      spell(new Spell("Fireball"))
      // assuming Spell has a constructor similar to this one
{ }

变量:

Wizard
(
    std::string name, unsigned int hp, unsigned int mp,
    std::string spellName, unsigned int spellCost, unsigned int spellDamage
)
    : name(std::move(name)),
      hp(hp), mp(mp),
      spell(new Spell(std::move(spellName), spellCost, spellDamage))
      // same assumption...
{ }

现在,您可以定义所有已经在外部的参数,然后将它们传入(现在有许多参数,但是更具灵活性)。

好的,现在还有很多要说的:内存泄漏(您不删除使用new创建的对象),智能指针(让删除自动完成),移动语义(关于{{1} }?–目前,您可能只是省略了...),封装(您的成员是公共的,应该是私有的),成员函数(以便您可以访问私有成员),是否内联以及隐藏实现细节(将代码拆分为标题和源代码),...

假设您稍后开始学习时会做完所有这些(但是,如果有兴趣,请发表评论,我会再发表一点...)。只是样式问题:不要将布尔值与true或false进行比较,只需直接使用条件即可:

std::move

与返回值类似,如果您仍然计算布尔值,则直接返回:

while (canGoOn(wiz1) == true && canGoOn(wiz2) == false) // bad style
//                                               ^^^^^
// changed just for demonstration purposes!

while (canGoOn(wiz1) && !canGoOn(wiz2))  // the way to go.
//                      ^ to check if condition is NOT met...
//                        again for demonstration only, not in your REAL code!

答案 1 :(得分:0)

这是我想到的。

死前都耗尽魔法的无限循环;)但是你可以解决

#include<random>
std::random_device rd;  //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()

int ThrowDie(int dieSize)
{
    std::uniform_int_distribution<> dis(1, dieSize);
    return dis(gen);
}

#include <string>
#include <utility>
class Spell {
    const int cost_base;
    const int cost_die;
    const int damage_base;
    const int damage_die;
public:
    const std::string name;

    Spell(const std::string& name, int cost_base, int cost_die,
        int damage_base, int damage_die)
        : name(name), cost_base(cost_base), cost_die(cost_die)
        , damage_base(damage_base), damage_die(damage_die) {}
    virtual ~Spell() = default;
    // returns <cost, damage>
    std::pair<int, int> Cast();
};

std::pair<int, int> Spell::Cast()
{
    return std::make_pair(
        cost_base + ThrowDie(cost_die),
        damage_base + ThrowDie(damage_die)
    );
}

class Fireball : public Spell {
public:
    Fireball() : Spell("FireBall", 6, 10, 6, 10) {}
    using Spell::Cast;
};

class Wizard
{
public:
    Wizard(const std::string& name);
    void cast(Spell spell, Wizard& opponent);
    bool IsAlive();
private:
    const std::string name;
    int healthPoints;
    int manaPoints;
};

Wizard::Wizard(const std::string& name)
    : name(name)
{
    healthPoints = 76 + ThrowDie(25);
    manaPoints = 76 + ThrowDie(25);
}

#include <iostream>
void Wizard::cast(Spell spell, Wizard& opponent)
{
    auto reqEff = spell.Cast();
    if (reqEff.first > manaPoints)
    {
        std::cout << name << " does not have enough mana points to cast " << spell.name << "\n";
    }
    else
    {
        manaPoints -= reqEff.first;
        opponent.healthPoints -= reqEff.second;
        std::cout << name << " casts " << spell.name << ", which does "
            << reqEff.second << " damage to " << opponent.name <<"\n";
    }
}

bool Wizard::IsAlive()
{
    if (healthPoints > 0)
    {
        //std::cout << name << " is still alive!\n"; \\ a lot of text...
        return true;
    }
    std::cout << name << " is dead!" << std::endl;
    return false;
}

#include <iostream>
int main()
{
    std::string name;
    std::cout << "Name the first wizard: ";
    std::cin >> name;
    Wizard wiz1(name);
    std::cout << "Name the second wizard: ";
    std::cin >> name;
    Wizard wiz2(name);

    // Battle start
    while (wiz1.IsAlive() && wiz2.IsAlive()) {
        wiz1.cast(Fireball(), wiz2);
        wiz2.cast(Fireball(), wiz1);
    }

    std::cin.ignore();
}

示例输出:

Name the first wizard: HarryPotter
Name the second wizard: Voldemort
HarryPotter casts FireBall, which does 13 damage to Voldemort
Voldemort casts FireBall, which does 11 damage to HarryPotter
HarryPotter casts FireBall, which does 12 damage to Voldemort
Voldemort casts FireBall, which does 12 damage to HarryPotter
HarryPotter casts FireBall, which does 7 damage to Voldemort
Voldemort casts FireBall, which does 16 damage to HarryPotter
HarryPotter casts FireBall, which does 8 damage to Voldemort
Voldemort casts FireBall, which does 10 damage to HarryPotter
HarryPotter casts FireBall, which does 8 damage to Voldemort
Voldemort casts FireBall, which does 14 damage to HarryPotter
HarryPotter casts FireBall, which does 16 damage to Voldemort
Voldemort casts FireBall, which does 16 damage to HarryPotter
HarryPotter casts FireBall, which does 16 damage to Voldemort
Voldemort casts FireBall, which does 11 damage to HarryPotter
HarryPotter casts FireBall, which does 14 damage to Voldemort
Voldemort casts FireBall, which does 10 damage to HarryPotter
HarryPotter is dead!