I am currently on the path of learning C++ and this is an example program I wrote for the course I'm taking. I know that there are things in here that probably makes your skin crawl if you're experienced in C/C++, heck the program isn't even finished, but I mainly need to know why I keep receiving this error after I enter my name: Exception thrown at 0x79FE395E (vcruntime140d.dll) in Learn.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC.
I know there is something wrong with the constructors and initializations of the member variables of the classes but I cannot pinpoint the problem, even with the debugger. I am running this in Visual Studio and it does initially run, but I realized it does not compile with GCC. Feel free to leave some code suggestions, but my main goal is to figure out the program-breaking issue.
#include <iostream>
#include <string>
#include <cstdio>
#include <array>
#include <cstdlib>
#include <ctime>
int getRandomNumber(int min, int max)
{
static constexpr double fraction{ 1.0 / (RAND_MAX + 1.0) };
return min + static_cast<int>((max - min + 1) * (std::rand() * fraction));
}
class Creature
{
protected:
std::string m_name;
char m_symbol;
int m_health;
int m_damage;
int m_gold_count;
public:
Creature(const std::string name, char symbol, int health, int damage, int gold_count) :
m_name{ name }, m_symbol{ symbol }, m_health{ health }, m_damage{ damage }, m_gold_count{ gold_count }
{}
const std::string getName() const { return m_name; }
const char getSymbol() const { return m_symbol; }
const int getHealth() const { return m_health; }
const int getDamage() const { return m_damage; }
const int getGold() const { return m_gold_count; }
void reduceHealth(int hp_taken) { m_health -= hp_taken; }
bool isDead() const { return m_health <= 0; }
void addGold(int gold) { m_gold_count += gold; }
};
class Player : public Creature
{
private:
int m_level = 1;
public:
Player(const std::string name) : Creature{ name, '@', 10, 1, 0}
{}
int getLevel() { return m_level; }
void levelUp() { ++m_level; ++m_damage; }
};
class Monster : public Creature
{
public:
enum class Type
{
dragon,
orc,
slime,
max_types
};
private:
static const Creature& getDefaultCreature(const Type& type)
{
static const std::array<Creature, static_cast<std::size_t>(Type::max_types)> monsterData{
{ {"dragon", 'D', 20, 4, 100}, {"orc", 'o', 4, 2, 25}, {"slime", 's', 1, 1,10}}
};
return monsterData.at(static_cast<std::size_t>(type));
}
public:
Monster(const Type& type) : Creature{getDefaultCreature(type)}
{
}
static const Monster& getRandomMonster() {
return Monster(static_cast<Type>(getRandomNumber(0, static_cast<int>(Type::max_types)-1)));
}
};
void attackPlayer(const Monster& monster, Player& player) {
std::cout << "The " << monster.getName() << " hit you for " << monster.getDamage() << ".\n";
player.reduceHealth(monster.getDamage());
}
void attackMonster(Monster& monster, Player& player) {
std::cout << "You hit the " << monster.getName() << " for " << player.getDamage() << ".\n";
monster.reduceHealth(player.getDamage());
if (monster.isDead()) {
printf("The %s is dead!\n", monster.getName());
player.levelUp();
player.addGold(monster.getGold());
if (player.getLevel() == 20)
printf("You won!");
return;
}
attackPlayer(monster, player);
}
void fightMonster(Player& player) {
Monster m{ Monster::getRandomMonster() };
printf("You have encountered a %s (%c).\n", m.getName(), m.getSymbol());
while (!m.isDead() && !player.isDead()) {
std::cout << "(R)un or (F)ight: ";
char choice;
std::cin >> choice;
if (choice == 'r' || choice == 'R') {
if (getRandomNumber(1, 2) == 1) {
std::cout << "You have successfully fled.\n";
return;
}
else {
std::cout << "You failed to flee.\n";
attackPlayer(m, player);
}
}
else if (choice == 'f' || choice == 'F')
{
attackMonster(m, player);
}
}
}
int main()
{
std::srand(time(NULL));
std::rand();
std::string name;
std::cout << "Enter Your Name: ";
std::cin >> name;
Player p{ name };
while (!p.isDead() && p.getLevel() < 20)
{
fightMonster(p);
}
if (p.isDead())
printf("You have died with %d gold and are level %d.", p.getGold(), p.getLevel());
}