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

Post Reply
jmcintyretech
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 34
Joined: Thu Mar 28, 2013 1:02 pm

Problem calling free() from another function [SOLVED]

Post by jmcintyretech »

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.
User avatar
bbguimaraes
Chaos Rift Junior
Chaos Rift Junior
Posts: 294
Joined: Wed Apr 11, 2012 4:34 pm
Programming Language of Choice: c++
Location: Brazil
Contact:

Re: Problem calling free() from another function

Post by bbguimaraes »

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

Re: Problem calling free() from another function

Post by jmcintyretech »

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.
User avatar
bbguimaraes
Chaos Rift Junior
Chaos Rift Junior
Posts: 294
Joined: Wed Apr 11, 2012 4:34 pm
Programming Language of Choice: c++
Location: Brazil
Contact:

Re: Problem calling free() from another function

Post by bbguimaraes »

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);
}
jmcintyretech
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 34
Joined: Thu Mar 28, 2013 1:02 pm

Re: Problem calling free() from another function

Post by jmcintyretech »

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.
User avatar
bbguimaraes
Chaos Rift Junior
Chaos Rift Junior
Posts: 294
Joined: Wed Apr 11, 2012 4:34 pm
Programming Language of Choice: c++
Location: Brazil
Contact:

Re: Problem calling free() from another function

Post by bbguimaraes »

\p/
Post Reply