-1

Question:

Why do I keep getting Segmentation faults after changing the way I declared and used my pointers to Objects?

They seem to be random in my opinion, but I'm sure there's a reason explaining this chaos.

Briefing:

I've been working on a Rogue-like game, very similar to NetHack, for several months and have reached another point where I've been stuck for days. The dungeon displays, and the Player can move around using w,a,s,d. When you come in contact with a Creature, you start attacking it. I had this working up to the point where the Creature <= 0. My problem was that I couldn't get the pointer of that creature to revert to a blank **Creature/NULL. I was told it had to do with how I declared the pointers in main.cpp so I tried a few suggestions and now I get seg faults constantly. For some reason I can't even move once after running the game most of the time. When I can move, I'm good until the Creature's HP <= 0.. then seg fault crashes the program. It has to be where the Creature dies, but I spent so much time trying to debug it and the debuggers were refusing to work. I swear I spent 10-15 hours with debugs and none would let me run my program!


I have a base class, Entity, that has 2 derived classes. These two derived classes are Item and Creature. These two sub-classes should be self explanatory.

  • Obviously Item has a few derived classes that add more specifics for the type of Item. Such as Armor, Food, Weapon, and so on..

  • Creature obviously has things that involve a life-like entity. With that being said, Creature has a derived class, Player, since there are only a few more things a Player can do.

Some things to Note:

  • I use a Factory method pattern that returns pointers to Creatures and another for Items. I'm just focused on Creature now.

  • In main.cpp I create a single Player object. Then I creature 3 pointers to Creatures, which is where/when the segmentation faults started happening. Here's how I had it before I changed it, followed by how I changed it.

    Creature * pCreature1 = NULL;
    Creature * pCreature2 = NULL;
    Creature * pCreature3 = NULL;
    

To:

    Creature * pCreature1 = new Creature();
    Creature * pCreature2 = new Creature();
    Creature * pCreature3 = new Creature();

The first way let me do everything as expected until the Creature needed to be removed from the level. I changed it to the second way due to people telling me that I was using the pointers wrong.

Code:

I'll add some of the code where I think issues may be arising. However, I've posted this question two other times and everyone bashed me for providing too much code and then not enough code.. hopefully to satisfy everyone and make this easier than how overwhelming I made it sound, I'll post where the Creature dies on here. I've uploaded everything to Cloud 9 so that everyone can view my files in their current state and run the program to see where everything's faulting.

The classes that use these pointers and could be causing the faults I believe are:

  • main.cpp
  • Creature
  • Player
  • Tile
  • DungeonLevel

I'm trying not to sound like I want someone to "give me the answer," but the last two time's I've asked essentially the same quest, everyone accuses me of that. I tried debugging and none of the debuggers on my Mac will update. I spent hours the other night trying this. You can see here: Why is the c++ standard library not working?

This really shouldn't be all that complex of a problem. I get stuck at a point and nothing I do reduces the errors :(

Any thoughts, tips, and suggestions will be greatly appreciated.

Here's the link to my cloud 9 project: http://c9.io/moddedlife/jhackpublic

Everything else on this page will be code snippets. Thanks again!

Player Attack Method:

void Player::attack(Creature * monster, Creature * player, std::mt19937 & randomGen,     DungeonLevel & dl){
    int monsterHit = monster->getHit(randomGen);
    int playerHit = getHit(randomGen);

    if ((monster->getHP() - playerHit) <= 0){
            playerHit = monster->getHP();
            cout << "Monster name: " << monster->getName() << endl;
            delete monster;
            monster = NULL;
            cout << "Monster name after: " << monster->getName() << endl;
    }
    else if ((player->getHP() - monsterHit) <= 0){
            monsterHit = player->getHP();
            //game over
    }

    cout << "You hit: " << playerHit << endl;
    player->setHP((player->getHP() - monsterHit));
    player->addXp(playerHit);

    if (monster != NULL){
            cout << "Monsters Hit: " << monsterHit << endl;
            monster->setHP((monster->getHP() - playerHit));
            cout << "Your HP: [" << player->getHP() << "]/[" << player->getMaxHP() << "]" << endl;
            cout << "Monsters HP: [" << monster->getHP() << "]/[" << monster->getMaxHP()     << "]" << end$
    }
    else {
            cout << "you Killed it!" << endl;
    }
    return;
}

Player Move Method:

I was going to put all of this code, but it's essentially the same - with only the direction changing.. each direction is around 30-50 lines. You can view all of the code for any of my files here: http://c9.io/moddedlife/jhackpublic

I WILL add the code here if using cloud 9 isn't allowed or something. I just thought it'd make it a whole lot easier than pasting blocks from several files.

Thanks

Community
  • 1
  • 1
JGeis
  • 31
  • 1
  • 2
  • 6
  • In general, you don't use pointers in C++. In particular, if you have a Java background, you need to get rid of the habit of using `new` everywhere. If you use pointers, you should also use "smart pointers" that are actually wrapper classes that prevent several common mistakes. – Ulrich Eckhardt Apr 28 '13 at 07:48

2 Answers2

1

First off, it is important to understand what a segmentation fault is and what causes them. I'm not trying to accuse you of not knowing either, but if you don't, the wikipedia page has some decent info:

A segmentation fault ... is generally an attempt to access memory that the CPU cannot physically address. (http://en.wikipedia.org/wiki/Segmentation_fault)

There are a lot of different ways to cause a segfault, but the most common (in my opinion anyways...my largest source of segfaults, I should say) way is by dereferencing a null pointer (or deleted/freed pointer).

Judging by a quick view of the code you posted, I see this:

delete monster;
monster = NULL;
cout << "Monster name after: " << monster->getName() << endl;

Remember, once you delete (or free) any allocated block of memory, you should NOT try to access it. By calling monster->getName() you are dereferencing a (now) NULL pointer--which then typically results in the ever so gentle but dreaded segmentation fault.

I can't promise that this is the ONLY offending line(s) (afterall, I only looked at the few snippets you posted), but it should be a start and hopefully you'll know what to look for in your code.

void ptr
  • 301
  • 2
  • 5
  • Ohhh ok. Thanks! I didn't realize I did that. I had that in there originally to test if the monster was actually "removed." – JGeis Apr 28 '13 at 01:49
0

It's too long story for me to find the exact problem, but deleteing a monster if it is dead seems suspicious. I recommend two things: make "dead" a state of a monster, and use smart pointers. no need to handle the NULL case, or deletion, at all.

Elazar
  • 20,415
  • 4
  • 46
  • 67
  • yeah sorry. It's a easy concept to grasp but due to the magnitude of the files, It needs some thorough explanation. Thanks, I'll try that out. – JGeis Apr 28 '13 at 01:31