C++ 引发异常:读取访问冲突[C+;+;]
嗨。我目前正在学习编程,所以暂且不考虑清理代码,我需要帮助让代码首先运行。另外,我为大量的代码块道歉。我不知道这些是否与问题无关,所以我还是把它们全部贴了出来 我们现在的课程是课堂,我想让两个巫师互相决斗。但在此之前,我需要为以下任一向导的属性赋值:C++ 引发异常:读取访问冲突[C+;+;],c++,C++,嗨。我目前正在学习编程,所以暂且不考虑清理代码,我需要帮助让代码首先运行。另外,我为大量的代码块道歉。我不知道这些是否与问题无关,所以我还是把它们全部贴了出来 我们现在的课程是课堂,我想让两个巫师互相决斗。但在此之前,我需要为以下任一向导的属性赋值: class Spell { public: string name; unsigned int cost; unsigned int dmg; }; class Wizard { public: string na
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;
}
intmain()
{
向导*wiz1=新建向导();
Wizard*wiz2=新建向导();
拼写*fireball1=新拼写();
拼写*fireball2=新拼写();
//指定属性值
srand(时间(空));
cout>wiz1->name;
赋值(wiz1,火球1);
cout>wiz2->name;
赋值(wiz2,fireball2);
//战斗开始!!
while(canGoOn(wiz1)==true&&canGoOn(wiz2)==true)
{
CastSpill(wiz1,wiz2);
CastSpill(wiz2,wiz1);
}
系统(“暂停”);
返回0;
}
为两个向导和两个法术赋值是可以的。然后,当它进入战斗循环时,会弹出以下错误:
Exception thrown: read access violation.
std::_String_alloc<std::_String_base_types<char,std::allocator<char> >
>::_Get_data(...) returned nullptr.
引发异常:读取访问冲突。
std::_String_alloc::_Get_data(…)返回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;
}
}
无效施法(法师*施法者,法师*敌人)
{
不能拼写->名称mp-=施法者->拼写->成本;
敌人->生命-=施法者->咒语->魔法咒语;
cout hp导致崩溃的问题是,您没有将拼写分配给向导的任何位置,因此指针默认初始化为空指针。在castSpell
函数中,您现在取消引用此空指针,试图访问无效内存(未定义的行为)
最好的方法是已经在构造函数中分配了拼写,这样你就不会陷入无效值的情况。有很多方法可以做到这一点:
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创建的对象)、智能指针(让删除自动完成)、移动语义(关于std::move
?——现在,你可能忽略它……),封装(你的成员是公共的,应该是私有的),成员函数(以便您可以访问私有成员),是否内联和隐藏实现细节(将代码拆分为头和源代码)
假设您稍后将了解所有这些内容,因为您刚刚开始学习(但如果有兴趣,请留下评论,我将发布更多…)。只是风格问题:不要将布尔值与true或false进行比较,直接使用条件:
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!
bool canGoOn(Wizard* wizard)
{
return wizard->hp > 0 && wizard->mp > 0; // just drop that if/else stuff around
}
与返回值类似,如果仍然计算布尔值,请直接返回:
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!
bool canGoOn(Wizard* wizard)
{
return wizard->hp > 0 && wizard->mp > 0; // just drop that if/else stuff around
}
这是我想到的
无限循环,当他们都在死前耗尽法力;)但你可以修复它
#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();
}
您将向导类的拼写成员分配到哪里?非主题:不要比较if(condition==true)
/if(condition==false)
;只需使用if(condition)
/if(!condition)
相反……请注意,您的成员变量是未签名的。当hps小于伤害时会发生什么?此外,向导和法术在免费存储区中使用new in main分配(请研究构造函数和RAII),但从未删除。为什么要在堆上创建对象?为什么不使用向导wiz1;
。并通过引用传递到函数?谢谢!所有答案都很有帮助,但这一个特别让我看到了我在需要做的事情上的错误(还有一些我没有注意到的错误).我在编码方面相对较新,所以这是非常有用的,谢谢(再次)!