freeing a matix

M

Michael Goerz

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 = calloc(number_of_columns, sizeof(double));
}
return matrix;
}


My guess was this,

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
 
B

Bill Medland

Michael said:
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 = calloc(number_of_columns, sizeof(double));
}
return matrix;
}


My guess was this,

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?
 
M

Michael Goerz

Bill said:
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;
}
 
B

Bill Medland

Michael said:
Bill said:
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.
 
S

Simon Biber

Michael said:
Bill said:
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.
 
S

Samuel Stearley

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 = &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.
 
S

Samuel Stearley

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 = &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.
 
B

Barry Schwarz

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
 
S

Samuel Stearley

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 = &temp[i*number_of_columns];
}

return ptr;

}




Barry said:
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
 
P

pete

Samuel said:
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 = calloc(columns, sizeof *matrix);
if (matrix == 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 */
 
B

Barry Schwarz

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));

This probably solves the problem for when sizeof(double) is twice the
sizeof(double*) but now when the ratio is four (4 bytes for a pointer
and 16 bytes for a double). It just introduces a thoroughly
unnecessary lack of portability.
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 = &temp[i*number_of_columns];
}

return ptr;

}




Barry said:
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



Remove del for email
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top