I am currently working on an assignment to implement Conways Game of Life in C++.
At the end of excution, I get the following message: free(): double free detected in tcache 2 Aborted (core dumped)
.
I think, this is due to the line delete[] pf
and the variable updatedField
. At least the problem does not occur, when I set the pointer to NULL. But at the same time, memory leakage occurs (according to using valgrind).
I compile the program using g++ -o main main.cpp
. I am working on a Linux Distribution.
Here is my code:
#include <iostream>
using namespace std;
const uint8_t ALIVE = 1;
const uint8_t DEAD = 0;
class Field
{
int width;
int height;
uint8_t *pf;
public:
int numberCellsAlive;
Field(int width_, int height_) : width(width_), height(height_)
{
pf = new uint8_t[width * height];
}
~Field()
{
pf = NULL; //This solves the problem, but leads to memory leakage
delete[] pf;
}
uint8_t get(uint32_t x, uint32_t y)
{
return pf[x + width * y];
}
void set(uint32_t x, uint32_t y, uint8_t state)
{
pf[x + width * y] = state;
}
int size()
{
return width;
}
};
int getRandomNumber(int size)
{
int randomNumber = (rand() % size);
return randomNumber;
}
int getNumberOfInitialAliveCellsFromPercentage(int size, int percentage)
{
return (size * size) * percentage / 100;
}
void fill(Field &field)
{
int size = field.size();
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
if (field.get(x, y) == ALIVE)
{
cout << " 0 ";
}
else
{
cout << " . ";
}
if (x == (size - 1))
{
cout << endl;
}
}
}
cout << endl;
}
Field init(Field &field, int percentage)
{
int size = field.size();
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
field.set(x, y, DEAD);
}
}
field.numberCellsAlive = getNumberOfInitialAliveCellsFromPercentage(size, percentage);
int randomX = getRandomNumber(size);
int randomY = getRandomNumber(size);
int f = 0;
srand((unsigned)time(0));
while (f < field.numberCellsAlive)
{
randomX = getRandomNumber(size);
randomY = getRandomNumber(size);
if (field.get(randomX, randomY) == DEAD)
{
f++;
field.set(randomX, randomY, ALIVE);
}
}
if (field.numberCellsAlive > 0)
{
fill(field);
}
return field;
}
// Checks neighbours if cell dies or stays alive.
Field checkNeighbours(Field &field)
{
int countLifes = 0;
int size = field.size();
Field updatedField = Field(size, size);
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
int neighbourCount = 0;
//vertical
if (y < size - 1)
{
if (field.get(x, y + 1) == ALIVE)
{
neighbourCount++;
}
}
if (y > 0)
{
if (field.get(x, y - 1) == ALIVE)
{
neighbourCount++;
}
}
//horizontal
if (x > 0)
{
if (field.get(x - 1, y) == ALIVE)
{
neighbourCount++;
}
}
if (x < size - 1)
{
if (field.get(x + 1, y) == ALIVE)
{
neighbourCount++;
}
}
//Diagonal upper left
if (y > 0 && x > 0)
{
if (field.get(x - 1, y - 1) == ALIVE)
{
neighbourCount++;
}
}
//Diagonal bottom right
if (x < size - 1 && y < size - 1)
{
if (field.get(x + 1, y + 1) == ALIVE)
{
neighbourCount++;
}
}
// Diagonal bottom left
if (y < size - 1 && x > 0)
{
if (field.get(x - 1, y + 1) == ALIVE)
{
neighbourCount++;
}
}
// Diagonal upper right
if (y > 0 && x < size - 1)
{
if (field.get(x + 1, y - 1) == ALIVE)
{
neighbourCount++;
}
}
if (field.get(x, y) == ALIVE)
{
if (neighbourCount == 2 || neighbourCount == 3)
{
countLifes++;
updatedField.set(x, y, ALIVE);
}
else
{
updatedField.set(x, y, DEAD);
}
}
else
{
if (neighbourCount == 3)
{
countLifes++;
updatedField.set(x, y, ALIVE);
}
else
{
updatedField.set(x, y, DEAD);
}
}
}
}
updatedField.numberCellsAlive = countLifes;
return updatedField;
}
int main(int argc, char *argv[])
{
if (argc < 4)
{
cout << "Illegal number of arguments" << endl
<< "Please enter exactly 3 arguments following this pattern: " << endl
<< "./main SIZE_OF_BOARD NUMBER_OF_GENERATIONS PERCENTAGE_OF_CELLS_ALIVE " << endl;
return 1;
}
//Clear console
cout << "\033[2J\033[1;1H";
int gen;
int size;
int percentage;
sscanf(argv[1], "%d", &size);
sscanf(argv[2], "%d", &gen);
sscanf(argv[3], "%d", &percentage);
Field field = Field(size, size);
field = init(field, percentage);
for (int i = 2; i <= gen; i++)
{
if ((!field.numberCellsAlive) > 0)
{
cout << "Game is over before time because no cells are alive. " << endl;
}
cin.get();
cout << "\033[2J\033[1;1H";
field = checkNeighbours(field);
cout << i << " Generation " << endl;
fill(field);
}
cin.get();
}
If somebody could point me in the right direction of how to solve this, I'd be very grateful!.