0

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?

theQman
  • 1,690
  • 6
  • 29
  • 52

4 Answers4

1

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] = {};
Digital_Reality
  • 4,488
  • 1
  • 29
  • 31
1
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.

Jim Balter
  • 16,163
  • 3
  • 43
  • 66
  • Thank you. I think this is pretty much what the problem is. I was freeing more than I was allocating, but it wasn't as obvious in my real code as it is in my sample code I put up here. what do you mean by getting rid of the first parameter to declareMatrix? How will that function know where the allocated memory should point to? – theQman Jan 22 '14 at 15:07
  • @theGman The first line of declareMatrix sets mymatrix; thus the value passed in is never used (and that value was undefined). You return mymatrix and set astruct[0].networkRep equal to it. There is no need for the first param. Consider that declareMatrix is just like malloc ... which does not take a pointer argument, it only returns a pointer value. – Jim Balter Jan 22 '14 at 19:26
  • @theGman An alternative implementation is to pass a pointer to a pointer and set the pointer via indirection ... see alk's answer for an example of this approach. – Jim Balter Jan 22 '14 at 19:35
0
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)

KARTHIK BHAT
  • 1,410
  • 13
  • 23
  • The call to `declareMatrix()` as per the OP's code is perfectly alright. – alk Jan 22 '14 at 06:47
  • 1
    OP's ?? i am just saying it's pointless to send the value contained in astruct[0].networkRep as he assigns new address to variable mymatrix as soon as he enters the function and send's the new address. – KARTHIK BHAT Jan 22 '14 at 07:20
  • Ahok, I see what you mean now and I do agree. Sry I missunderstood you. (OP == "Original Posting" or "Original Poster") – alk Jan 22 '14 at 07:25
  • Thank you. I'm intializing more of the struct arrays later on in the code, so it's not just astruct[0].networkRep that gets declared. Can you explain how I should be passing my array to declareMatrix? I thought the pointer is being passed, memory is allocated to it, and then returned. It seems to work everywhere else that I use it... – theQman Jan 22 '14 at 15:03
  • @theGman Your thought is quite wrong. You are passing in an uninitialized value to the mymatrix parameter. You then immediately overwrite that with the result of malloc, and end up returning that, and setting your pointer to that. The param is unnecessary and useless. If you don't understand this, keep looking at it and trace what happens. If you still don't understand, then you have some fundamental misunderstanding of how function parameters work. To set a pointer through an argument, you would have to pass the *address* of the pointer, and store indirectly (i.e., into `*pointertopointer`). – Jim Balter Jan 22 '14 at 19:31
  • @theGman For an example of storing a pointer through an argument, see alk's answer. – Jim Balter Jan 22 '14 at 19:33
0

To index and count an unsigned integer type is enough. size_tis 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);
  }
}
Community
  • 1
  • 1
alk
  • 69,737
  • 10
  • 105
  • 255