tags:

views:

102

answers:

3

I am having trouble freeing a pointer in a pointer array (values).

typedef struct MyStruct{  char** values;  }MyStruct;

In C, I create dynamic array.

JSDictionary **array = (JSDictionary **)malloc(sizeof(JSDictionary *) * numRows);

The resultSet should be an array of JSDictionary pointers. I create the struct like:

JSDictionary * newJSDictionaryWithSize(unsigned int size)

{
JSDictionary *new = malloc(sizeof(JSDictionary));
    printf("new %p\n", self);
new->_size = size;
new->count = 0;

new->values = (char **) malloc(sizeof(char *) * size);
for(unsigned int i = 0; i < size; i++){
    new->values[i] = (char *)malloc(sizeof(char *));
}

return new;
}

Everything creates and works fine. It's the free that gives me a problem.

void deallocJSDictionary(struct JSDictionary *self)

{
printf("dealloc %p\n", self);
for(unsigned int i = 0; i < self->_size; i++){
    printf("free %p\n", &self->values[i]);
    free(self->values[i]);
}
free(self->values);
free(self);

}

I get a pointer being freed was not allocated error. The pointer being passed in shows the same memory address as the one that I created and added to the array. The values pointer (in debugger) shows the same memory address in the dealloc function as it did when I created it. The problem is trying to free the first point in the values array. Any ideas why the first point in the values pointer array is different?

+4  A: 

I see two problems so far. First:

new->values[i] = (char *)malloc(sizeof(char *));

This line allocates a single pointer - probably not what you want. Should likely be something like:

new->values[i] = malloc( MAX_SIZE_OF_VALUE );

I.e. a buffer to hold the value. You can also allocate one big chuck to keep all values and just offset into that memory.

Second:

printf("free %p\n", &self->values[i]);
free(self->values[i]);

This prints and tries to free(3) two different pointers. First is the address of the second.

As for the actual deallocation error - do you have assignments like this in the code that manages the dictionary?

dict->values[i] = some_value;

If so - you are overriding pointers to (and leaking) allocated memory with pointers to probably stack or static memory. You have to copy the the value into the "value-buffer". Something like:

strlcpy( dict->values[i], some_value, MAX_SIZE_OF_VALUE );

Hope this helps.

Nikolai N Fetissov
good point on the dealloc error. I was overriding the pointer with a new one, I forgot about that.
joels
+1  A: 

The problem is likely in your memory allocation code. The following line

new->values = (char **) malloc(sizeof(char *) * size);

allocates an array of char pointers, containing size elements. Therefore, this is unnecessary:

for(unsigned int i = 0; i < size; i++){
    new->values[i] = (char *)malloc(sizeof(char *));
}

What you are doing here is storing a char ** cast to a char * in each element of the new->values array. That is, you are allocating enough memory to store a char * value and then storing a pointer to that memory in the new->values array. I'm guessing you did this in error, because

new->values = (char **) malloc(sizeof(char *) * size);

has already allocated enough memory for each element of the new->values array.

What I'm guessing you want is:

for(unsigned int i = 0; i < size; i++){
    new->values[i] = (char *)malloc(sizeof(char) * MAX_STRING_LENTH);
}

to create a char buffer of MAX_STRING_LENGTH elements for each element of the new->values array. This allows you to store a string in each element, and your freeing code should work fine.

Alternatively, if the elements of new->values are set somewhere else, then you probably don't want to be freeing them in your deconstructor, unless they were allocated dynamically and you know no other references to them exist at that point.

tomit
+1  A: 

There's nothing inherently wrong with your functions. They compile fine, albeit after a few syntax errors and they produce output as expected. So as others have pointed out, you're possibly assigning to the allocated pointers, data that wasn't allocated (i.e. stack data) or you're passing in JSDictionary structures that weren't properly allocated in the first place via newJSDictionaryWithSize.

As a quick test, do an alloc/dealloc on just one JSDictionary to verify that your functions work.

JSDictionary *ptr = newJSDictionaryWithSize(10);
deallocJSDictionary(ptr);
zdawg