views:

89

answers:

1

Hello. I'm struggling to find why I can't free a memory block. Something must be wrong with the pointer. A memory block for a structure is made in a function and the pointer used is stored in an array. Later the pointer is taken from the array to be used to free the memory.

I've figured out which free it is. I've placed "//This one" next to it.

#include <stdlib.h>

typedef enum {
    INT = 0,
    FLOAT = 1,
    STRING = 2,
    NONE = 3,
    BOOL = 4
} TYPE;

typedef struct {
    TYPE type;
    void * data;
} Variable;

typedef Variable ** var; //Convenience typedef for pointer to variable pointer

typedef struct {
    size_t size;
    Variable *** pool; //Pointer to the array of pointers to the Variable structure pointers. Pointer required for memory allocation and array consists of pointers to pointers so the pointers to the Variable structures can be changed throughtout different functions.
} VarPool; //Variable pools will just be used to deallocate all variables at the end of a scope

VarPool * global_pool; //Pool for global scope
VarPool ** pool_stack; //Keeps track of pools in stack
unsigned int pool_stack_size;

void init_pool_stack(){
    pool_stack = malloc(sizeof(VarPool *)); //Start with global_pool
    pool_stack_size = 1;
    global_pool = malloc(sizeof(VarPool));
    pool_stack[0] = global_pool;
    global_pool->pool = NULL;
    global_pool->size = 0;
}

Variable ** new_var(){ //Makes new variable
    Variable ** return_variable;
    Variable * new_variable = malloc(sizeof(Variable));
    VarPool * var_pool = pool_stack[pool_stack_size-1]; //Current variable pool on top of stack
    var_pool->size++;
    var_pool->pool = realloc(var_pool->pool,var_pool->size*sizeof(Variable **));
    return_variable = &new_variable;
    var_pool->pool[var_pool->size - 1] = return_variable;
    return return_variable; //Return pointer to new pointer so pointer can be changed to NULL when deleted
}
void empty_pool(){ //Frees all data from variable pool
    VarPool * var_pool = pool_stack[pool_stack_size-1]; //Current pool on top of stack
    for (int x = 0; x < var_pool->size; x++) {
        free(*var_pool->pool[x]); //Free variable data
    }
    free(var_pool->pool); //Free pool variable array
    free(var_pool); //This one
    pool_stack_size--;
    pool_stack = realloc(pool_stack, pool_stack_size*sizeof(VarPool *));
}

int main (int argc, const char * argv[]) {
    init_pool_stack();
    new_var();
    empty_pool(); //Finally empty globals pool which will deallocate pool_stack
    return 0;
}

Thank you for any help.

+7  A: 

in new_var() you have (simplified)

Variable ** new_var(){ //Makes new variable
  Variable ** return_variable;
  Variable * new_variable = malloc(sizeof(Variable));

  return_variable = &new_variable;
  return return_variable;
}

The value returned from this function becomes invalid once the function ends. The address of a local variable is only meaningful while that variable exists.

pmg
THank you for the answer. You are right. It just hit me. The new_variable address is invalid unless allocated. I need to allocate it. I'll do that now...
Matthew Mitchell
I allocated the pointer to the new_variable address but I need to free it. I can't do that in the empty pool function as this fails - free(var_pool->pool[x]); It should be a copy of the pointer to the allocated pointer to the variable made on the first line of new_var().
Matthew Mitchell
@Matthew - or... you could pass in Variable** into new var and do something like `*newVar = malloc(sizeof(Variable));`
SB
At first I was going to pass in pointers like that but then I wanted the library to be used as simply and elegant so I thought I should make the functions handle data by themselves only requiring the user to take references of data to process as needed. I'm just confused right now as to why I can't free the memory block for the structure pointer when I store it in the pool array (The triple pointer one). It's just a copy of the return_variable pointer which points to the allocated pointer (It allocates it now but not in the code above.)
Matthew Mitchell
@Matthew: once you have it working try to get rid of the global variables. Define them inside `main` and pass them (or their addresses: another `*`) to functions.
pmg
I changed - return_variable = - to - *return_variable = new_variable; - and no more errors. I was changing the pointer to the allocated memory space to point to the, later invalid, new_variable address. I need to change the allocated pointer to become the new_variable pointer. I think that's it. Hurrah! Thank you everyone. I'll do more tests of-course.
Matthew Mitchell
What is wrong with global variables? They will mean using the library will be a lot easier as the library functions access the global data themselves.
Matthew Mitchell
Global variables are bad. Why you dont use it as a parameter in all your functions?
But why are they bad? I never understand why people say that all the time. I find them extremely useful. In this case they will make the library much easier to use. I find the idea of passing data like that unnecessary.
Matthew Mitchell
@Matthew: will you (or anybody who uses the library) **never** want to have 2 independent pools?
pmg
The pools are put on the stack which works along side the call stack and that is all which is needed. The whole idea of this library is to replicate features of python so I can make a python to c converter. The library will be included for the converted programs.
Matthew Mitchell
Will you, sometime, want to use threads with your python converter? :P
pmg
Yes, I probably will. I can always create a new array holding stacks for each thread. For now I don't need that. That would be a pointer to an array of pointers to an array of pointers to VarPool structures. Another triple pointer. :D
Matthew Mitchell