Problem calling free() from another function [SOLVED]

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Problem calling free() from another function [SOLVED]

Postby jmcintyretech on Tue Oct 21, 2014 8:40 pm

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[i] = 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[i]);
}

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[i] = 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[i]);
}

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 11:09 am, edited 2 times in total.
jmcintyretech
Chaos Rift Newbie
Chaos Rift Newbie
 
Posts: 34
Joined: Thu Mar 28, 2013 2:02 pm

Re: Problem calling free() from another function

Postby bbguimaraes on Wed Oct 22, 2014 7:52 am

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';
When freeing, the process is analogous:
free(grid[0]);
free(grid[1]);
free(grid[2]);
free(grid);
Note this is not the most efficient way of doing this.
User avatar
bbguimaraes
Chaos Rift Junior
Chaos Rift Junior
 
Posts: 324
Joined: Wed Apr 11, 2012 5:34 pm
Location: Brazil

Re: Problem calling free() from another function

Postby jmcintyretech on Wed Oct 22, 2014 5:37 pm

So I'm still having trouble passing this Grid** in and out of functions. I asked one of my profs and she noticed this:

Code: Select all
grid = malloc(GRID_SIZE * sizeof(Grid));


should be

Code: Select all
grid = malloc(GRID_SIZE * sizeof(Grid*));


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.
jmcintyretech
Chaos Rift Newbie
Chaos Rift Newbie
 
Posts: 34
Joined: Thu Mar 28, 2013 2:02 pm

Re: Problem calling free() from another function

Postby bbguimaraes on Thu Oct 23, 2014 6:41 am

jmcintyretech wrote:should be
Code: Select all
grid = malloc(GRID_SIZE * sizeof(Grid*));

My bad :oops:
jmcintyretech wrote:So I'm still having trouble passing this Grid** in and out of functions.

Remember a pointer-to-pointer is still passed by value:
#include <stdio.h>
#include <stdlib.h>


void f0(char ** pp) {
pp = malloc(3);
}

void f1(char *** pp) {
*pp = malloc(3);
}

int main() {
char ** pp = NULL;
f0(pp);
printf("%p\n", pp); // prints NULL
f1(&pp);
printf("%p\n", pp); // prints some address
}
If you're in c++, you could use a reference (less explicit, IMHO):
void f2(char **& pp) { // called with f2(pp)
pp = malloc(3);
}
User avatar
bbguimaraes
Chaos Rift Junior
Chaos Rift Junior
 
Posts: 324
Joined: Wed Apr 11, 2012 5:34 pm
Location: Brazil

Re: Problem calling free() from another function

Postby jmcintyretech on Thu Oct 23, 2014 11:25 am

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)[i] = (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)[i]);
}

free(*grid);
}
Last edited by jmcintyretech on Fri Mar 18, 2016 11:09 am, edited 1 time in total.
jmcintyretech
Chaos Rift Newbie
Chaos Rift Newbie
 
Posts: 34
Joined: Thu Mar 28, 2013 2:02 pm

Re: Problem calling free() from another function

Postby bbguimaraes on Thu Oct 23, 2014 11:36 am

\p/
User avatar
bbguimaraes
Chaos Rift Junior
Chaos Rift Junior
 
Posts: 324
Joined: Wed Apr 11, 2012 5:34 pm
Location: Brazil


Return to Programming Discussion

Who is online

Users browsing this forum: No registered users and 1 guest

cron