Velocity Reviews > freeing a matix

# freeing a matix

Michael Goerz
Guest
Posts: n/a

 12-01-2006
Hi,

how can I free a matrix that was created with this function:

double **my_matrix(long number_of_rows, long number_of_columns){
double **matrix;
matrix = calloc(number_of_rows, sizeof(double *));
int i;
for (i = 0; i < number_of_rows; i++){
matrix[i] = calloc(number_of_columns, sizeof(double));
}
return matrix;
}

void my_free_matrix(double **m, long number_of_rows, long
number_of_columns){
int row;
for (row = 0; row < number_of_rows; row++){
free(m[row]);
}
free(m);
}

but it fails with "*** glibc detected *** double free or corruption
(out): 0xbfbbaa58 ***"

Many Thanks,
Michael Goerz

Bill Medland
Guest
Posts: n/a

 12-01-2006
Michael Goerz wrote:

> Hi,
>
> how can I free a matrix that was created with this function:
>
> double **my_matrix(long number_of_rows, long number_of_columns){
> double **matrix;
> matrix = calloc(number_of_rows, sizeof(double *));
> int i;
> for (i = 0; i < number_of_rows; i++){
> matrix[i] = calloc(number_of_columns, sizeof(double));
> }
> return matrix;
> }
>
>
>
> void my_free_matrix(double **m, long number_of_rows, long
> number_of_columns){
> int row;
> for (row = 0; row < number_of_rows; row++){
> free(m[row]);
> }
> free(m);
> }
>
> but it fails with "*** glibc detected *** double free or corruption
> (out): 0xbfbbaa58 ***"
>
> Many Thanks,
> Michael Goerz

Looks right to me. Have you tried running under a debugger to watch it?
Possibly the number of rows disagrees between the allocation and the
release?
--
Bill Medland

Michael Goerz
Guest
Posts: n/a

 12-01-2006
Bill Medland wrote:
>> void my_free_matrix(double **m, long number_of_rows, long
>> number_of_columns){
>> int row;
>> for (row = 0; row < number_of_rows; row++){
>> free(m[row]);
>> }
>> free(m);
>> }
>>
>> but it fails with "*** glibc detected *** double free or corruption
>> (out): 0xbfbbaa58 ***"
>>

> Looks right to me. Have you tried running under a debugger to watch it?
> Possibly the number of rows disagrees between the allocation and the
> release?

Yeah, I think the problem was that I put a static array in one of the
matrix rows. I guess I just can't do that, can I?

int main(){
double **m = my_matrix(4,3); // create a 4x3 matrix
m[0][1] = 5.0;
double row2[] = {1.0, 2.0, 3.0, 4.0};
m[1] = row2; // leave this out, and it doesn't crash
my_free_matrix(m, 4, 3);
return 0;
}

Bill Medland
Guest
Posts: n/a

 12-01-2006
Michael Goerz wrote:

> Bill Medland wrote:
>>> void my_free_matrix(double **m, long number_of_rows, long
>>> number_of_columns){
>>> int row;
>>> for (row = 0; row < number_of_rows; row++){
>>> free(m[row]);
>>> }
>>> free(m);
>>> }
>>>
>>> but it fails with "*** glibc detected *** double free or corruption
>>> (out): 0xbfbbaa58 ***"
>>>

>> Looks right to me. Have you tried running under a debugger to watch it?
>> Possibly the number of rows disagrees between the allocation and the
>> release?

>
> Yeah, I think the problem was that I put a static array in one of the
> matrix rows. I guess I just can't do that, can I?
>

Um, No, you can't

> int main(){
> double **m = my_matrix(4,3); // create a 4x3 matrix
> m[0][1] = 5.0;
> double row2[] = {1.0, 2.0, 3.0, 4.0};
> m[1] = row2; // leave this out, and it doesn't crash
> my_free_matrix(m, 4, 3);
> return 0;
> }

Basically with C you need to understand pointers and what they point to.

m is a pointer. It points to the first element of the array. Each element
of that array is itself a pointer to the first element of an array.

What you did was to allocate all the space you needed and then change the
pointer that was the second pointer in the top level array.

Then when you went to deallocate the matrix two things happened;
a. my_free_matrix tried to release that array on the stack (which it didn't
like doing)
b. my_free_matrix did NOT try and release the space you allocated (because
you dropped the pointer to it).

What you should have done is copy the elements of row2 into the space
pointed to by m[1].

Hopefully that helps.

--
Bill Medland

Simon Biber
Guest
Posts: n/a

 12-02-2006
Michael Goerz wrote:
> Bill Medland wrote:
>>> void my_free_matrix(double **m, long number_of_rows, long
>>> number_of_columns){
>>> int row;
>>> for (row = 0; row < number_of_rows; row++){
>>> free(m[row]);
>>> }
>>> free(m);
>>> }
>>>
>>> but it fails with "*** glibc detected *** double free or corruption
>>> (out): 0xbfbbaa58 ***"
>>>

>> Looks right to me. Have you tried running under a debugger to watch it?
>> Possibly the number of rows disagrees between the allocation and the
>> release?

>
> Yeah, I think the problem was that I put a static array in one of the
> matrix rows. I guess I just can't do that, can I?

You can do that, but you need to keep track of which rows need freeing
and which don't.

> int main(){
> double **m = my_matrix(4,3); // create a 4x3 matrix
> m[0][1] = 5.0;
> double row2[] = {1.0, 2.0, 3.0, 4.0};
> m[1] = row2; // leave this out, and it doesn't crash
> my_free_matrix(m, 4, 3);
> return 0;
> }

Try this:

void my_free_matrix(double **m, long number_of_rows,
long number_of_columns, char *dont_free) {
int row;
for (row = 0; row < number_of_rows; row++){
if(!dont_free[row]) free(m[row]);
}
free(m);
}

int main() {
char *dont_free = calloc(4, sizeof *dont_free);
double **m = my_matrix(4, 3);
m[0][1] = 5.0;
double row2[] = {1.0, 2.0, 3.0};
dont_free[1] = 1; // register row 1 as no free
free(m[1]); // do free here to avoid mem leak
m[1] = row2;
my_free_matrix(m, 4, 3, dont_free);
free(dont_free);
return 0;
}

Note that this code, and your my_matrix function should really check for
failure of calloc; it returns a null pointer if the memory is not available.

--
Simon.

Samuel Stearley
Guest
Posts: n/a

 12-03-2006
I'd write this as

double ** my_matrix(long number_of_rows, long number_of_columns){
double ** ptr;
double * temp;
long i;

/* All data is in a single malloc. First are the pointers, then the
doubles */
ptr = (double **)malloc(number_of_rows * sizeof(double *) +
number_of_rows * number_of_columns * sizeof(double));

temp = (double *)&ptr[number_of_rows]; /* get a pointer to where the
doubles are stored */

for (i = 0; i < number_of_rows; i++)
{
ptr[i] = &temp[i*number_of_columns];
}

return ptr;
}

Then it only takes a single free to delete it.
And you can insert rows with an assignment to a static array without
error.

Michael Goerz wrote:
> Hi,
>
> how can I free a matrix that was created with this function:
>
> double **my_matrix(long number_of_rows, long number_of_columns){
> double **matrix;
> matrix = calloc(number_of_rows, sizeof(double *));
> int i;
> for (i = 0; i < number_of_rows; i++){
> matrix[i] = calloc(number_of_columns, sizeof(double));
> }
> return matrix;
> }
>
>
>
> void my_free_matrix(double **m, long number_of_rows, long
> number_of_columns){
> int row;
> for (row = 0; row < number_of_rows; row++){
> free(m[row]);
> }
> free(m);
> }
>
> but it fails with "*** glibc detected *** double free or corruption
> (out): 0xbfbbaa58 ***"
>
> Many Thanks,
> Michael Goerz

Samuel Stearley
Guest
Posts: n/a

 12-03-2006
I'd write this as

double ** my_matrix(long number_of_rows, long number_of_columns){
double ** ptr;
double * temp;
long i;

/* All data is in a single malloc. First are the pointers, then the
doubles */
ptr = (double **)malloc(number_of_rows * sizeof(double *) +
number_of_rows * number_of_columns * sizeof(double));

temp = (double *)&ptr[number_of_rows]; /* get a pointer to where the
doubles are stored */

for (i = 0; i < number_of_rows; i++)
{
ptr[i] = &temp[i*number_of_columns];
}

return ptr;
}

Then it only takes a single free to delete it.
And you can insert rows with an assignment to a static array without
error.

Michael Goerz wrote:
> Hi,
>
> how can I free a matrix that was created with this function:
>
> double **my_matrix(long number_of_rows, long number_of_columns){
> double **matrix;
> matrix = calloc(number_of_rows, sizeof(double *));
> int i;
> for (i = 0; i < number_of_rows; i++){
> matrix[i] = calloc(number_of_columns, sizeof(double));
> }
> return matrix;
> }
>
>
>
> void my_free_matrix(double **m, long number_of_rows, long
> number_of_columns){
> int row;
> for (row = 0; row < number_of_rows; row++){
> free(m[row]);
> }
> free(m);
> }
>
> but it fails with "*** glibc detected *** double free or corruption
> (out): 0xbfbbaa58 ***"
>
> Many Thanks,
> Michael Goerz

Barry Schwarz
Guest
Posts: n/a

 12-03-2006
On 2 Dec 2006 18:39:31 -0800, "Samuel Stearley" <(E-Mail Removed)>
wrote:

>I'd write this as
>
>double ** my_matrix(long number_of_rows, long number_of_columns){
> double ** ptr;
> double * temp;
> long i;
>
> /* All data is in a single malloc. First are the pointers, then the
>doubles */
> ptr = (double **)malloc(number_of_rows * sizeof(double *) +
>number_of_rows * number_of_columns * sizeof(double));
>
> temp = (double *)&ptr[number_of_rows]; /* get a pointer to where the
>doubles are stored */

On a system where sizeof(double*) is 4, sizeof(double) is 8, and each
is required to be aligned to a multiple of its size, this is
guaranteed to fail when number_of_rows is odd.

Remove del for email

Samuel Stearley
Guest
Posts: n/a

 12-03-2006
Oops

double ** my_matrix(long number_of_rows, long number_of_columns){
double ** ptr;
double * temp;
long alignment;
long i;

/* All data is in a single malloc. First are the pointers, then the
doubles */
alignment = number_of_rows &1;
ptr = (double **)malloc( (number_of_rows + alignment) * sizeof(double
*) +
number_of_rows * number_of_columns * sizeof(double));

temp = (double *)&ptr[number_of_rows + alignment]; /* get a pointer to
where the
doubles are stored */

for (i = 0; i < number_of_rows; i++)
{
ptr[i] = &temp[i*number_of_columns];
}

return ptr;

}

Barry Schwarz wrote:
> On 2 Dec 2006 18:39:31 -0800, "Samuel Stearley" <(E-Mail Removed)>
> wrote:
>
> >I'd write this as
> >
> >double ** my_matrix(long number_of_rows, long number_of_columns){
> > double ** ptr;
> > double * temp;
> > long i;
> >
> > /* All data is in a single malloc. First are the pointers, then the
> >doubles */
> > ptr = (double **)malloc(number_of_rows * sizeof(double *) +
> >number_of_rows * number_of_columns * sizeof(double));
> >
> > temp = (double *)&ptr[number_of_rows]; /* get a pointer to where the
> >doubles are stored */

>
> On a system where sizeof(double*) is 4, sizeof(double) is 8, and each
> is required to be aligned to a multiple of its size, this is
> guaranteed to fail when number_of_rows is odd.
>
>
> Remove del for email

pete
Guest
Posts: n/a

 12-04-2006
Samuel Stearley wrote:
>
> Oops
>
> double ** my_matrix(long number_of_rows, long number_of_columns){

Are we still doing this problem?

/* BEGIN new.c */

#include <stdio.h>
#include <stdlib.h>

double **my_matrix(unsigned rows, unsigned columns);
void my_free_matrix(double **m, unsigned rows);
void init_matrix(double **m, unsigned rows, unsigned columns);
void show_matrix(double **m, unsigned rows, unsigned columns);

int main(void)
{
unsigned rows = 5;
unsigned columns = 7;
double **matrix;

matrix = my_matrix(rows, columns);
if (matrix != NULL) {
init_matrix(matrix, rows, columns);
show_matrix(matrix, rows, columns);
my_free_matrix(matrix, rows);
puts("\nThe matrix has been freed.");
} else {
puts("matrix == NULL");
}
return 0;
}

double **my_matrix(unsigned rows, unsigned columns)
{
double **matrix;
unsigned i;

matrix = calloc(rows, sizeof *matrix);
if (matrix != NULL) {
for (i = 0; i != rows; ++i) {
matrix[i] = calloc(columns, sizeof *matrix[i]);
if (matrix[i] == NULL) {
my_free_matrix(matrix, i);
matrix = NULL;
break;
}
}
}
return matrix;
}

void my_free_matrix(double **m, unsigned rows)
{
while (rows-- != 0) {
free(m[rows]);
}
free(m);
}

void init_matrix(double **m, unsigned rows, unsigned columns)
{
unsigned r, c;

for (r = 0; r != rows; ++r) {
for (c = 0; c != columns; ++c) {
m[r][c] = r + c + 0.5;
}
}
}

void show_matrix(double **m, unsigned rows, unsigned columns)
{
unsigned r, c;

for (r = 0; r != rows; ++r) {
for (c = 0; c != columns; ++c) {
printf("%f ", m[r][c]);
}
putchar('\n');
}
}

/* END new.c */

--
pete