I'm getting a segmentation fault when I try to free memory I allocate for a 2d array. The following causes a segmentation fault:
/* This function is the main game loop
*/
void game_loop()
{
/* Store the user input for logic */
Input input = NONE;
/* Create game variables */
Grid** grid;
int score;
int goal;
/* Initialize a new game */
new_game(grid, &score, &goal);
while(true)
{
/* Get user input */
input = get_input();
if (input == QUIT)
{
end_game(grid);
break;
}
}
/* Go to the score loop */
score_loop();
}
/* This function allocates a grid for a new game and initializes game data
Param: grid
Param: score
Param: goal
*/
void new_game(Grid** grid , int* score, int* goal)
{
grid = malloc(GRID_SIZE * GRID_SIZE * sizeof(Grid));
int i;
for (i = 0; i < GRID_SIZE; i++)
{
grid = malloc(GRID_SIZE * sizeof(Grid));
}
/* Test load some data into this 2d array */
int r;
int c;
for(r = 0; r < GRID_SIZE; r++)
{
for (c = 0; c < GRID_SIZE; c++)
{
grid[r][c] = ONE;
printf("%d ", grid[r][c]);
}
printf("\n");
}
*score = 0;
*goal = 15;
}
/* This function frees memory from a game
Param: grid
*/
void end_game(Grid** grid)
{
int i;
for (i = 0; i < GRID_SIZE; i++)
{
free(grid);
}
free(grid);
}
So the main game loop calls new_game(grid, &score, &goal), loops until the user quits (I haven't coded any of the actual game stuff yet) and then calls end_game(grid) when the user quits.
Now, when testing, this does NOT cause a segmentation fault:
/* This function allocates a grid for a new game and initializes game data
Param: grid
Param: score
Param: goal
*/
void new_game(Grid** grid , int* score, int* goal)
{
grid = malloc(GRID_SIZE * GRID_SIZE * sizeof(Grid));
int i;
for (i = 0; i < GRID_SIZE; i++)
{
grid = malloc(GRID_SIZE * sizeof(Grid));
}
/* Test load some data into this 2d array */
int r;
int c;
for(r = 0; r < GRID_SIZE; r++)
{
for (c = 0; c < GRID_SIZE; c++)
{
grid[r][c] = ONE;
printf("%d ", grid[r][c]);
}
printf("\n");
}
*score = 0;
*goal = 15;
/* Test free the 2d array allocated in this function */
for (i = 0; i < GRID_SIZE; i++)
{
free(grid);
}
free(grid);
}
My question: why do I get an error when I pass the Grid** 2d array to an external function and free, but do not get an error when I deallocate in the same location that I allocated the memory from? Am I not passing the 2d array "pointer pointer" properly?
If any of the above does make sense, please ask and I will clarify.
Last edited by jmcintyretech on Fri Mar 18, 2016 10:09 am, edited 2 times in total.
grid should be just GRID_SIZE * sizeof(Grid) in size. You misunderstood how a 2d array is implemented using pointers to pointers. The "first level" pointer (grid) points to an array of pointers of size equal to the number of rows. Each pointer in this array (grid) points to another array of size equal to the number of columns. A diagram:
// If you want the grid to be:
// a b c d
// e f g h
// i j k l
// You will have the following structure:
// One array is allocated just to store the addresses of each row (a pointer to
// pointers).
char ** grid = malloc(3 * sizeof(char));
// At each position of this array, another array is allocated to store the
// actual data of each row.
grid[0] = malloc(4 * sizeof(char));
grid[0][0] = 'a'; grid[0][1] = 'b'; grid[0][2] = 'c'; grid[0][3] = 'd';
grid[1] = malloc(4 * sizeof(char));
grid[1][0] = 'e'; grid[1][1] = 'f'; grid[1][2] = 'g'; grid[1][3] = 'h';
grid[2] = malloc(4 * sizeof(char));
grid[2][0] = 'i'; grid[1][2] = 'j'; grid[2][2] = 'k'; grid[2][3] = 'l';
Which I originally missed. I do understand that I am creating a pointer to an array of pointers, basically. So her explanation made sense. I'll keep you guys posted on anything further I run into.
Got it! I asked a professor at school and she caught this as well.
Here are the working functions:
/* This function is the main entry point for the program */
int main()
{
Grid** grid;
new_game(&grid);
end_game(&grid);
return 0;
}
/* This function allocates a 2d array */
void new_game(Grid*** grid)
{
*grid = (Grid**) malloc(GRID_SIZE * sizeof(Grid*));
int i;
for (i = 0; i < GRID_SIZE; i++)
{
(*grid) = (Grid*) malloc(GRID_SIZE * sizeof(Grid));
}
}
/* This function deallocates a 2d array */
void end_game(Grid*** grid)
{
int i;
for (i = 0; i < GRID_SIZE; i++)
{
free((*grid));
}
free(*grid);
}
Last edited by jmcintyretech on Fri Mar 18, 2016 10:09 am, edited 1 time in total.