Error EXC_BAD_ACCESS (code=1, address=0x0)

Hello Everyone,

I have been programming a small RPG game based on the console interface. Recently I started programming the way monsters are created using classes. The logic of my program is as follows:

There are ‘families’ of monsters (eg. rats, lions etc.)
Depending on the player’s level, he fights different monsters from each family.
For instance, at lvl 1 if he encounters a rat, it will be a “wounded rat”. But if he is lvl 100, he will encounter an ‘overpowered rat’
The object of the class carries the information about the monster.
Each object is created by a function, that checks the level.

So my problem is that sometimes when the algorithm tries to create a monster, the program randomly crashes and starts the lldb on the console. The error message is: Error EXC_BAD_ACCESS (code=1, address=0x0).

There are no breakpoints anywhere. Furthermore, I noticed that the error occurs every time the variable nmonster == 0. The IDE that I am using is Xcode 8.2. I suspect that I have made a dumb mistake somewhere…

I have isolated and simplified the code so you don’t have to see parts that do not affect the error:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <array>

#include "unistd.h"
#include "time.h"
#include "math.h"
#include "stdlib.h"
#include "stdio.h"
#include <cstdlib>

#include "MonsterClass.hpp"

using namespace std;

MonsterClass generate_monster(int level, string monsters[], int mlength);

int main(){
    int level = 1;
    string monsters[] = {"rat", "snake", "empty"};
    int monsters_length = sizeof( monsters ) / sizeof( monsters[ 0 ] );
    monsters_length--;
    cout<<monsters_length<<endl;

    
    while(true){
        sleep(1);
        int generate_chance;
        time_t seconds;
        time(&seconds);
        srand((unsigned int) seconds);
        generate_chance = rand() % (100 - 0 + 1) + 0;
        cout<<"Generate Chance: "<<generate_chance<<endl;
        if(generate_chance <= 80){
            cout<<"An enemy was spotted"<<endl;
            MonsterClass enemy = generate_monster(level, monsters, monsters_length);
        }
    }

    return 0;
}


MonsterClass generate_monster(int level, string monsters[], int length){
    bool category_not_found = 0;
    string category_monster;
    MonsterClass* enemy = nullptr;
    
    
    do{
        sleep(1);
        
        int nmonster;//number of the monster category
        time_t seconds;
        time(&seconds);
        srand((unsigned int) seconds);
        nmonster = rand() % (length - 0 + 1) + 0;
        cout<<"Monster category number: "<<nmonster<<endl;
        
        category_monster = monsters[nmonster-1];
        
        if(level == 1){
            if (category_monster == "rat"){
                enemy = new MonsterClass ("wounded rat", 1);
                cout<<"You encountered a "<<enemy->name<<endl;
            }
            else if(category_monster == "snake"){
                enemy = new MonsterClass ("wounded rat", 1);
                cout<<"You encountered a "<<enemy->name<<endl;
            }
            else{
                category_not_found = 1;
                
            }
            
        }

        
        if((category_monster == "empty") || (category_monster == "") || (category_not_found = 1) || (nmonster = 0)){
            break;
        }
    }while(true);
    
    return *enemy;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//MonsterClass.cpp
#include "MonsterClass.hpp"
#include <iostream>
#include <fstream>
#include <string>

#include "time.h"
#include "math.h"
#include "stdlib.h"
#include "stdio.h"

using namespace std;


MonsterClass::MonsterClass(string n, int l){
    name = n;
    level = l;
}


MonsterClass::~MonsterClass(){
    
    
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//MonsterClass.hpp
#ifndef MonsterClass_hpp
#define MonsterClass_hpp

#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;

class MonsterClass{
    
public:
    
    MonsterClass(string n, int l);
    
    string name;
    int level;
    
    ~MonsterClass();
    
    
};



#endif


Any help is appreciated.
1
2
string monsters[] = {"rat", "snake", "empty"};
int monsters_length = sizeof( monsters ) / sizeof( monsters[ 0 ] );
You can't use sizeof for objects, better would be:
1
2
vector<string> monsters = {"rat", "snake", "empty"};
int monsters_length = monsters.size();


I think the biggest problem is that the enemy pointer in generate_monster can be null when you reach the end of the function. Returning the object pointed to by a null pointer is very likely what's causing the crash.

Do you really need to use a pointer inside that function? Even if you make sure the pointer is not null when you return you would still have a memory leak because you haven't used delete.

If you plan on using inheritance, with multiple different monster classes, I can understand if you use pointers, but then you probably also want the function to return a pointer. In that case i would recommend using a smart pointer such as std::unique_ptr to help managing the lifetime of the monster object.


You also have a problem with picking a random monster category.
1
2
nmonster = rand() % (length - 0 + 1) + 0; // Generates a random number x ; 0 ≤ x ≤ length
category_monster = monsters[nmonster-1]; // This will not work if nmonster == 0. 


Thomas1965 wrote:
You can't use sizeof for objects

Of course you can. The way he calculates the length of the array is perfectly valid.
That said, I totally support the recommendation to use vectors.
Last edited on
Thomas1965 wrote:
You can't use sizeof for objects
you can.

Take a look at line 81:

if((category_monster == "empty") || (category_monster == "") || (category_not_found = 1) || (nmonster = 0))

See that you assign instead of compare? I suggest to use the constant value left:

1 = category_not_found // compiler error

Even if this look unfamiliar, it prevents you from accidental assignments.

The crash will certainly happen when enemy -> nullptr. Why don't you return a pointer? This way you generate memory leaks.
Thank you for the replies.

As Peter said the problem was here:
nmonster = rand() % (length - 0 + 1) + 0; // Generates a random number x ; 0 ≤ x ≤ length
category_monster = monsters[nmonster-1]; // This will not work if nmonster == 0.

I changed that and now it works fine. However, am I new to classes so I do not fully undestand what you mean with 'momory leaks'.

Thanks a lot
Topic archived. No new replies allowed.