Moving pointers in a matrix

Hi, I'm doing a project that has a 2d array of pointers of Base class (Critter), and it holds objects of two derived classes (Ant and Doodlebug). Now, everything seems great, until I try to move an object. For example, I try to move Ant from matrix[1][1] to matrix[1][2].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//main() function
Critter* critters[20][20];
Grid grid(critters);

grid.initialize(critters);

    //print Matrix
    grid.printMatrix(critters);

    //THIS IS THE END OF INITIALIZATION

    while(!grid.isFinished(critters))
    {
        grid.doTurn(critters);

        grid.printMatrix(critters);

        cin.get();
    }


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
//part of Grid::doTurn() thats creating problems
int m = critters[i][j]->move();

                if(critters[i][j]->info == 'D')
                {
                    switch(m)
                    {
                    case 0:
                        if((i != 0) && (critters[i-1][j]->info == 'A'))
                        {
                            //critters[i-1][j] = critters[i][j];
                            //delete critters[i][j];
                            //critters[i - 1][j]->eat(1);
                        }
                        break;
                    case 1:
                        if((j != 19) && (critters[i][j+1]->info == 'A'))
                        {
                            //critters[i][j+1] = critters[i][j];
                            //delete critters[i][j];
                            //critters[i][j+1]->eat(1);
                        }
                        break;
                    case 2:
                        if((i != 19) && (critters[i+1][j]->info == 'A'))
                        {
                            //critters[i+1][j] = critters[i][j];
                            //delete critters[i][j];
                            //critters[i+1][j]->eat(1);
                        }
                        break;
                    case 3:
                        if((j != 0) && (critters[i][j-1]->info == 'A'))
                        {
                            //critters[i][j-1] = critters[i][j];
                            //delete critters[i][j];
                            //critters[i][j-1]->eat(1);
                        }
                        break;
                    }
                }
           


Whenever I uncomment something, it crashes, and I don't see why delete critters[i][j] would crash, but it does.

Any ideas?
Last edited on
You are deleting specific elements from critters but do you ensure that the particular pointer won't ever be dereferenced again ?

Also it would help if you post your entire code.
Have you tried running this in a debugger and find what line causes trouble ?
Last edited on
The problem is that you are deleting the critter object immediately after you've changed its position in the matrix. So, for example, at line 35 you set critters[i][j-1] to point to the same memory as critters[i][j] points to.

Then, at line 36, you delete the object stored in that memory - meaning that both critters[i][j] and critters[i][j-1] are no longer pointing to a valid object in memory.

Then, at line 37, you try and access the memory at critters[i][j-1] as if it still held a valid object, which it doesn't - causing the crash.

I don't understand why you're deleting that Critter object, when clearly it's still supposed to exist. Do you understand what deleting an object actually does?
Last edited on
I'm trying to create something like a game, where a snake eats something and moves to its place, and clear one space on it's end. Like "move" trough the matrix. In case command 0 is move up, 1 is move right, 2 is down...

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
89
90
91
92
void Grid::doTurn(Critter *critters[20][20])
{
    for(int i = 0; i < 20; i++)
    {
        for(int j = 0; j < 20; j++)
        {
            if(critters[i][j] != NULL)
            {
                bool b = critters[i][j]->breed();

                if(b)
                {
                    //try to place another critter above current one
                    if((i != 0) && (critters[i-1][j] == NULL))
                    {
                        if(critters[i][j]->info == 'D')
                            critters[i-1][j] = new Doodlebug;
                        else
                            critters[i-1][j] = new Ant;
                    }
                    else if((j != 19) && (critters[i][j+1] == NULL))
                    {
                        //try to place new critter to the right
                        if(critters[i][j]->info == 'D')
                            critters[i][j+1] = new Doodlebug;
                        else
                            critters[i][j+1] = new Ant;
                    }
                    else if((i != 19) && (critters[i+1][j] == NULL))
                    {
                        //try to place beneath
                        if(critters[i][j]->info == 'D')
                            critters[i+1][j] = new Doodlebug;
                        else
                            critters[i+1][j] = new Ant;
                    }
                    else if((j != 0) && (critters[i][j-1] == NULL))
                    {
                        //try to place to the left
                        if(critters[i][j]->info == 'D')
                            critters[i][j-1] = new Doodlebug;
                        else
                            critters[i][j-1] = new Ant;
                    }
                }
                //THIS CONCLUDES BREEDING PART

                int m = critters[i][j]->move();

                if(critters[i][j]->info == 'D')
                {
                    switch(m)
                    {
                    case 0:
                        if((i != 0) && (critters[i-1][j]->info == 'A'))
                        {
                            delete critters[i-1][j];
                            critters[i-1][j] = critters[i][j];
                            critters[i - 1][j]->eat(1);
                        }
                        break;
                    case 1:
                        if((j != 19) && (critters[i][j+1]->info == 'A'))
                        {
                            delete critters[i][j+1];
                            critters[i][j+1] = critters[i][j];
                            critters[i][j+1]->eat(1);
                        }
                        break;
                    case 2:
                        if((i != 19) && (critters[i+1][j]->info == 'A'))
                        {
                            delete critters[i+1][j];
                            critters[i+1][j] = critters[i][j];
                            critters[i + 1][j]->eat(1);
                        }
                        break;
                    case 3:
                        if((j != 0) && (critters[i][j-1]->info == 'A'))
                        {
                            delete critters[i][j-1];
                            critters[i][j-1] = critters[i][j];
                            critters[i][j-1]->eat(1);
                        }
                        break;
                    }
                }
            }
        }
    }
}
I;m trying to make one object move over other object, "eats" it. So this loop creates problems. Case 0 moves object up, 1 to the right...

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
                int m = critters[i][j]->move();

                if(critters[i][j]->info == 'D')
                {
                    switch(m)
                    {
                    case 0:
                        if((i != 0) && (critters[i-1][j]->info == 'A'))
                        {
                            delete critters[i-1][j];
                            critters[i-1][j] = critters[i][j];
                            critters[i - 1][j]->eat(1);
                        }
                        break;
                    case 1:
                        if((j != 19) && (critters[i][j+1]->info == 'A'))
                        {
                            delete critters[i][j+1];
                            critters[i][j+1] = critters[i][j];
                            critters[i][j+1]->eat(1);
                        }
                        break;
                    case 2:
                        if((i != 19) && (critters[i+1][j]->info == 'A'))
                        {
                            delete critters[i+1][j];
                            critters[i+1][j] = critters[i][j];
                            critters[i + 1][j]->eat(1);
                        }
                        break;
                    case 3:
                        if((j != 0) && (critters[i][j-1]->info == 'A'))
                        {
                            delete critters[i][j-1];
                            critters[i][j-1] = critters[i][j];
                            critters[i][j-1]->eat(1);
                        }
                        break;
                    }
                }
            }
        }
Once you've processed an action, you have two elements of your matrix pointing to the same Critter. E.g. at line 35, you set critters[i][j-1] to point to the same object as critters[i][j]. Is that actually what you want?

So this loop creates problems

Which do you think is more likely to result in us being able to help you better:

1) Telling us as clearly as possible exactly what the problems you're seeing are,

OR

2) Not telling us what the problems are, and hoping we're all able to read your mind telepathically?

Tough question, I know.
Last edited on
Sorry for not being clear. I wish to make one pointer point at what his next is pointing at, and then dereference that next one. II wish to move an object trough the matrix that way.
closed account (48T7M4Gy)
A critters position might be at cell i,j on the grid but does that make it critter[i][j]?
It doesnt, but I want to put it there. First delete whats on that place and then move object to that pointer place.

Can anyone give me an example of how to do it?

Thanks!
closed account (48T7M4Gy)
Ok, that's what I thought. So forgetting for a moment what the board looks like, what information is recorded via by having a critter[i][j]? We need to see the code for the Base class you refer to.

I am guessing but I suspect you are confusing the board status with the properties and methods associated with critters. You need a 2d board but not 2d critters. If a critter (an instance/object of the Critter class) knows its position then a collision can be determined if that correspond to an occupied board position. If the board knows what is at every one of its cells then the game can be made to work.

If I'm right with my guess at what you are trying to do I wouldn't be looking at pointers I'd be looking at applying structs or classes. :)
Base class
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
class Critter
{
public:
    int timeToBreedCounter;
    int timeToDeathCounter;
    int breedLimit;
    int liveLimit;
    char info;

    Critter();
    ~Critter();

    void eat(int);
    int move();
    bool breed();
    bool died();
};

Critter::Critter()
{
    //initialize counters to zero
    timeToBreedCounter = 0;
    timeToDeathCounter = 0;
}

Critter::~Critter()
{

}

void Critter::eat(int x)
{
    if((info == 'D') && (x == 1))
    {
        timeToDeathCounter = 0;
    }
    else timeToDeathCounter++;
}

int Critter::move()
{
    return ((rand() % 4) + 1);
}


bool Critter::breed()
{
    //if its ant, and its time for it to breed
    if(info == 'A' && timeToBreedCounter == breedLimit)
    {
        timeToBreedCounter = 0;
        return true;
    }
    else if(info == 'D' && timeToBreedCounter == breedLimit)
    {
        //if its dBug, and its time for it to breed
        timeToBreedCounter = 0;
        return true;
    }

    //otherwise just increment timer
    timeToBreedCounter++;

    return false;
}


bool Critter::died()
{
    if(timeToDeathCounter >= liveLimit)
        return true;

    return false;
}



Ant class:
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

class Ant : public Critter
{
public:

    Ant();
    ~Ant();
};

Ant::Ant()
{
    liveLimit = 10;
    breedLimit = 3;

    timeToBreedCounter = 0;
    timeToDeathCounter = 0;
    //doodlebug constructor is the same, but info = 'D' and Limits above hold different values
    info = 'A';
}

Ant::~Ant()
{

}



Grid class:
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
class Grid
{
public:
    Grid(Critter *critters[20][20]);
    ~Grid();

    void initialize(Critter *critters[20][20]);
    void printMatrix(Critter *critters[20][20]);
    bool isFinished(Critter *critters[20][20]);
    void doTurn(Critter *critters[20][20]);
};

Grid::Grid(Critter *critters[20][20])
{
    //initialize all to zero
    for(int i = 0; i < 20; i++)
    {
        for(int j = 0; j < 20; j++)
        {
            critters[i][j] = NULL;
        }
    }
}

void Grid::doTurn(Critter *critters[20][20])
{
    for(int i = 0; i < 20; i++)
    {
        for(int j = 0; j < 20; j++)
        {
            if(critters[i][j] != NULL)
            {
                bool b = critters[i][j]->breed();

                if(b)
                {
                    //try to place another critter above current one
                    if((i != 0) && (critters[i-1][j] == NULL))
                    {
                        if(critters[i][j]->info == 'D')
                            critters[i-1][j] = new Doodlebug;
                        else
                            critters[i-1][j] = new Ant;
                    }
                    else if((j != 19) && (critters[i][j+1] == NULL))
                    {
                        //try to place new critter to the right
                        if(critters[i][j]->info == 'D')
                            critters[i][j+1] = new Doodlebug;
                        else
                            critters[i][j+1] = new Ant;
                    }
                    else if((i != 19) && (critters[i+1][j] == NULL))
                    {
                        //try to place beneath
                        if(critters[i][j]->info == 'D')
                            critters[i+1][j] = new Doodlebug;
                        else
                            critters[i+1][j] = new Ant;
                    }
                    else if((j != 0) && (critters[i][j-1] == NULL))
                    {
                        //try to place to the left
                        if(critters[i][j]->info == 'D')
                            critters[i][j-1] = new Doodlebug;
                        else
                            critters[i][j-1] = new Ant;
                    }
                }
                //THIS CONCLUDES BREEDING PART

                int m = critters[i][j]->move();

                if(critters[i][j]->info == 'D')
                {
                    switch(m)
                    {
                    case 0:
                        if((i != 0) && (critters[i-1][j]->info == 'A'))
                        {
                            //move object, Doodlebug "eats" Ant above itself
                        }
                        break;
                    case 1:
                        if((j != 19) && (critters[i][j+1]->info == 'A'))
                        {
                            //move object. Doodlebug eats ant to the right of itself
                        }
                        break;
                    case 2:
                        if((i != 19) && (critters[i+1][j]->info == 'A'))
                        {

                        }
                        break;
                    case 3:
                        if((j != 0) && (critters[i][j-1]->info == 'A'))
                        {

                        }
                        break;
                    }
                }
            }
        }
    }
}


What do you think can be changed?
closed account (48T7M4Gy)
Well, I don't want to suggest anything more than a Critter (base class) possibly knows it's current coordinates on the board. So it just has 2 private int's with corresponding get's and set's related to position, assuming a Critter can only be in one place at a time.

The rest follows because if board[i][j] records a critter of some sort moves, collisions etc show up directly by interrogating the board.

In fact, it is probably better that the board is made the sole repository for the critters position. (This assumes all critters have to be on the board ... maybe ... your call)

So, for example if board[3][5] is about to be ant[15]; and if board[3][5] is already accommodating doodlebug[22] then, depending on strength etc one or the other Critter gets chomped.
That sounds nice, but I would have to change a lot of things, to create separate arrays of each derived class etc. I was thinking of implementing copy constructors, and then deleting memory allocated for Ant, creating Doodlebug object on that same memory (same place in matrix) with copy constructor, so all timers would stay the same, and then deleting original doodlebug object.

Can that be done?
closed account (48T7M4Gy)
That sounds nice,

It's OK if you're not convinced but the practicalities are to ask yourself the question where are you going with what you have so far.

but I would have to change a lot of things

For me, I don't believe there are many changes because the model is very simple. Another factor which often crops up here is whether you want to dig the hole deeper. Your call. :]

to create separate arrays of each derived class

There is no restriction on how you manufacture, store and otherwise manage you zoo. Arrays aren't the only way. Vectors, individual variables, whatever you like. I could have said Ant ant_first, ant01 and Doodlebug pave_a_road but I wish you luck keeping track of them.

Why are you fixed on what the board comprises? Instead of a 2d array of integers it is a 2d array of Critter objects. If a Critter of any kind is alive, dead or otherwise no longer viable just flag it with a bool alive attribute of true or false. At worst if a cell has 100 Critters on it just consider the ones with alive == true. Whatever. The point is they don't have to necessarily be (physically) deleted from memory other than when they go out of scope.

What I'd suggest is make up simple classes of a couple of lines based on what you have, then place one or two on a simple board and try to move an ant from one space to another. Forget about all the strength stuff, just move a Critter and test whether it is moving properly and possibly to another cell which is already occupied.

I think timers are towards the least of the concerns here.

Good luck and all the best with it. :)
Thanks for all your help. I will maybe try to work on it from that way. Maybe use vectors...

But, one thing I dont really understand is how come my solution doesnt work? I set a cell to point to some other cell, and in that I copy an object to that place. Then I delete original object.

How come does this crash, how can i fix it?
closed account (48T7M4Gy)
I'll have a look but it will take a while.
Thanks a lot! Looking forward to your reply!
closed account (48T7M4Gy)
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <iostream>

class Critter
{
private:
    char info;

public:
    Critter(char someInfo = '*'){ info = someInfo;}
    ~Critter(){ };
    char getInfo();
    void setInfo( char someInfo){ info = someInfo; };
};

char Critter::getInfo(){ return info;}

class Grid
{
private:
    int rows;
    int cols;
    Critter empty = Critter('*');
    Critter* **matrix;

public:
    Grid(const int rows = 1, const int cols = 1);
    ~Grid();
    
    bool move( int aCurrentX, int aCurrentY, int aNewX, int aNewY );
    void display();
    bool isVacant(const int, const int);
    void set(Critter*, int, int);
};

Grid::Grid(const int nRows, const int nCols)
{
    rows = nRows;
    cols = nCols;
    
    matrix = new Critter* *[nRows];
    for (int j=0; j < nRows; j++)
        matrix[j] = new Critter*[nCols];
    
    for(int i = 0; i < rows; i++)
    {
        for(int j = 0; j < cols; j++)
            matrix[i][j] = &empty;
    }
}

Grid::~Grid()
{
    for(int i = 0; i < rows; i++ )
        delete [] matrix[i];
    delete [] matrix;
}

void Grid::set(Critter* aCritter, int aXpos, int aYpos)
{
    matrix[aXpos][aYpos] = aCritter;
}

void Grid::display()
{
    for( int i = 0; i < rows; i++ )
    {
        for( int j = 0; j < cols; j++ )
            std::cout << matrix[i][j]->getInfo() << ' ';
        std::cout << '\n';
    }
    std::cout << '\n';
}

bool Grid::isVacant(int x, int y)
{
    return matrix[x][y]->getInfo() == '*';
}

bool Grid::move(int aCurrentX, int aCurrentY, int aNewX, int aNewY)
{
    if (isVacant(aNewX,aNewY))
    {
        matrix[aNewX][aNewY] = matrix[aCurrentX][aCurrentY];
        matrix[aCurrentX][aCurrentY] = &empty;
        return true;
    }
    else
        return false;
}

int main()
{
    //Setup grid - populate with empty Critters
    const int rows = 5;
    const int cols = 7;
    Grid grid(rows, cols);
    
    grid.display();
    
    // Add some random critters 50% coverage
    for(int i = 0; i < rows * cols / 2; i++)
    {
        Critter* dummy = new Critter((char)(i % 26 + 'A'));
        grid.set( dummy, rand() % rows, rand() % cols);
    }
    
    // Add just a single critter
    Critter* Bill = new Critter('+');
    grid.set( Bill, 4, 4);
    grid.display();
    
    // Move a Critter at selected grid to new position
    grid.move(0,2,1,4);
    grid.display();
    
    // Move another Critter but output error message if collision occurs
    if( !grid.move(1,4,2,3) )
        std::cout << "Error: Can't move there.\n";
    grid.display();
    
    // Move 'Bill'
    grid.move(4,4,1,1);
    grid.display();
    
    Bill -> setInfo('?');
    grid.display();
    
    std::cout << Bill -> getInfo() << '\n';
    
    return 0;
}

* * * * * * * 
* * * * * * * 
* * * * * * * 
* * * * * * * 
* * * * * * * 

* O M * * * * 
* E J I * * H 
* * F D * P * 
* * * Q * N * 
* * * * + L G 

* O * * * * * 
* E J I M * H 
* * F D * P * 
* * * Q * N * 
* * * * + L G 

Error: Can't move there.
* O * * * * * 
* E J I M * H 
* * F D * P * 
* * * Q * N * 
* * * * + L G 

* O * * * * * 
* E J I M * H 
* * F D * P * 
* * * Q * N * 
* * * * + L G 

* O * * * * * 
* E J I M * H 
* * F D * P * 
* * * Q * N * 
* * * * ? L G 

?
 
Exit code: 0 (normal program termination)
Last edited on
Sorry for the late reply, but it did help! In the end I did it my way -> implementing copy constructors, and dealing with Grid.

Thanks again! Really appreciate it!
closed account (48T7M4Gy)
Cheers, all the best :)
Topic archived. No new replies allowed.