I am trying to up my C-game. I am currently using the book "Mastering Algorithms with C" by Kyle Loudon. Currently I am looking into data structures, specifically Stacks. The code example I will use here is not straight from the book but is slightly modified for readibility. I have looked online but have not found any answer to my questions.
A common rule I often hear about in C-programming is "whoever allocated memory is responsible for freeing it". This seems like a simple rule to follow. However, when I tried to create a function to push a new stack element on top of the stack, I got a bit unsure.
The code
StackElmt is the element to reside in a Stack. Before any operation can be performed on a Stack, stack_init needs to be run. After that stack_push pushes new elements on the top of the stack and stack_pop pops them from the stack.
typedef struct StackElmt_ {
void *data;
struct StackElmt_ *next;
}StackElmt;
typedef struct Stack_
{
int size;
StackElmt *top;
}Stack;
void stack_init(Stack *stack)
{
stack->size = 0;
stack->top = NULL;
}
void stack_push(Stack *stack, void *data)
{
StackElmt *element = calloc(1, sizeof(StackElmt));
element->data = data;
element->next = stack->top;
stack->top = element;
stack->size++;
}
void stack_pop(Stack *stack, StackElmt **element)
{
*element = stack->top;
stack->top = (*element)->next;
stack->size--;
}
Problem description
I find it very odd that stack_push allocates memory to the heap but the stack_pop does not free it. I feel like if stack_push allocates the memory, memory management becomes the responsibility of the developer of these Stack functions and not the user.
Instead, I would like to do something like this:
void stack_push(Stack *stack, StackElmt *element, void *data)
{
element->data = data;
element->next = stack->top;
stack->top = element;
stack->size++;
}
where a pointer to a StackElmt is input and users can choose themselves how to allocate it.
Summary
My questions are:
- Is the code where memory is allocated in stack_push() but not freed in stack_pop() considered good design? Would having a clear comment in stack_pop() that the user is responsible for the StackElmt memory make the design better?
- In the book, there is also a function called "destroy_stack" that destroys the stack. In it, "stack_pop" and a user-defined function pointed to by a pointer (recommended to be free) are run for every element in the Stack. Does this "destroy"-function make it clearer from a user perspective who is responsible for memory management?
- Is it better to have memory allocation completely by the user (see my modified stack_push) or completelt by the program?
Thank you all in advance!