简体   繁体   中英

How to free dynamic 2d array that's in a struct?

I have a dynamic 2d array inside this struct:

struct mystruct{
    int mySize;
    int **networkRep;
};

In my code block I use it as follows:

struct myStruct astruct[100];
astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200);
// do stuff...
int i;
for(i=0; i<100; i++)
    freeMatrix(astruct[i].networkRep, 200);

This is how I declare the 2d array:

int** declareMatrix(int **mymatrix, int rows, int columns)
{
    mymatrix = (int**) malloc(rows*sizeof(int*));
    if (mymatrix==NULL)
        printf("Error allocating memory!\n");
    int i,j;
    for (i = 0; i < rows; i++)
        mymatrix[i] = (int*) malloc(columns*sizeof(int));

    for(i=0; i<rows; i++){
        for(j=0; j<columns; j++){
            mymatrix[i][j] = 0;
        }
    }
    return mymatrix;
}

And this is how I free the 2d array:

void freeMatrix(int **matrix, int rows)
{
    int i;
    for (i = 0; i < rows; i++){
        free(matrix[i]);
    }
    free(matrix);
    matrix = NULL;
}

The strange behvior that I'm seeing is that when I compile and run my program everything looks OK. But when I pipe the stdout to a txt file, I'm getting a seg fault. However, the seg fault doesn't occur if I comment out the loop containing the "freeMatrix" call. What am I doing wrong?

I don't see any problem in free code, except, freeMatrix get called for 100 times whereas your allocation is just 1 .

So, either you allocate as below:

 for(int i=0; i<100; i++) //Notice looping over 100 elements. 
    astruct[i].networkRep = declareMatrix(astruct[i].networkRep, 200, 200);

Or, free for only 0th element which you have allocated in your original code.

freeMatrix(astruct[0].networkRep, 200);

On sidenote: Initialize your astruct array .

mystruct astruct[100] = {};
struct myStruct astruct[100];

astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200);

// do stuff...
int i;
for(i=0; i<100; i++)
    freeMatrix(astruct[i].networkRep, 200);

You allocated one astruct but free 100 of them; that will crash if any of the 99 extra ones isn't NULL, which probably happens when you do your redirection. (Since astruct is on the stack, it will contain whatever was left there.)

Other issues:

You're using numeric literals rather than manifest constants ... define NUMROWS and NUMCOLS and use them consistently.

Get rid of the first parameter to declareMatrix ... you pass a value but never use it.

In freeMatrix,

matrix = NULL;

does nothing. With optimization turned on, the compiler won't even generate any code.

if (mymatrix==NULL)
    printf("Error allocating memory!\n");

You should exit(1) upon error, otherwise your program will crash and you may not even see the error message because a) stdout is buffered and b) you're redirecting it to a file. Which is also a reason to write error messages to stderr, not stdout.

astruct[0].networkRep = declareMatrix(astruct[0].networkRep, 200, 200); 

your not passing the address of the pointer. It just passes the value in the memory to the function which is unncessary.

And your only initializing first variable of struct but while you are trying to free the memory you are unallocating memory which is not yet allocated (astruct[1] and so on till 100 ).

When you use a malloc , it actually allocates a bit more memory than you you specified. extra memory is used to store information such as the size of block, and a link to the next free/used block and sometimes some guard data that helps the system to detect if you write past the end of your allocated block.

If you pass in a different address, it will access memory that contains garbage, and hence its behaviour is undefined (but most frequently will result in a crash)

To index and count an unsigned integer type is enough. size_t is the type of choice for this as it is guaranteed to be larger enough to address/index every byte of memory/array's element on the target machine.

struct mystruct
{
  size_t mySize;
  int ** networkRep;
};

Always properly initialise variables:

struct myStruct astruct[100] = {0};

Several issues with the allocator:

A possible to do this:

int declareMatrix(int *** pmymatrix, size_t rows, size_t columns)
{
    int result = 0; /* Be optimistc. */

    assert(NULL != pmatrix);

    *pmymatrix = malloc(rows * sizeof(**pmymatrix));
    if (NULL == *pmymatrix)
    {
      perror("malloc() failed");
      result = -1;

      goto lblExit;
    }

    { 
      size_t i, j;
      for (i = 0; i < rows; i++)
      {
        (*pmymatrix)[i] = malloc(columns * sizeof(***pmymatrix));
        if (NULL ==   (*pmymatrix)[i])
        {
          perror("malloc() failed");
          freeMatrix(pmymatrix); /* Clean up. */
          result = -1;

          goto lblExit;
        }

        for(i = 0; i < rows; ++i)
        {
          for(j = 0; j < columns; ++j)
          {
            (*pmymatrix)[i][j] = 0;
          }
        }
      }
    }

lblExit:
    return 0;
}

Two issues for the de-allocator:

  • Mark it's work as done be properly de-initilaising the pointer.
  • Perform validation of input prior to acting on it.

A possible to do this:

void freeMatrix(int *** pmatrix, size_t rows)
{
  if (NULL != pmatrix)
  {
    if (NULL != *pmatrix)
    {
      size_t i;
      for (i = 0; i < rows; ++i)
      {
        free((*pmatrix)[i]);
      }
    }

    free(*pmatrix);
    *pmatrix = NULL;
  }
}

Then use the stuff like this:

struct myStruct astruct[100] = {0};

...

int result = declareMatrix(&astruct[0].networkRep, 200, 200);
if (0 != result)
{
  fprintf("declareMatrix() failed.\n");
}
else
{
// Note: Arriving here has only the 1st element of astruct initialised! */
// do stuff...
}

{
  size_t i;
  for(i = 0; i < 100; ++i)
  {
    freeMatrix(&astruct[i].networkRep, 200);
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM