【发布时间】:2021-01-07 16:34:45
【问题描述】:
我正在努力提升我的 C 级游戏。我目前正在使用 Kyle Loudon 的《用 C 语言掌握算法》一书。目前我正在研究数据结构,特别是堆栈。我将在这里使用的代码示例并非直接来自本书,而是为了便于阅读而稍作修改。我上网查了一下,但没有找到任何问题的答案。
我在 C 编程中经常听到的一条常见规则是“分配内存的人负责释放它”。这似乎是一个简单的规则。但是,当我尝试创建一个函数以将新的堆栈元素压入堆栈顶部时,我有点不确定。
代码
StackElmt 是驻留在 Stack 中的元素。在对堆栈执行任何操作之前,需要运行 stack_init。之后,stack_push 将新元素压入栈顶,stack_pop 将它们从栈中弹出。
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--;
}
问题描述
我觉得很奇怪 stack_push 将内存分配给堆,但 stack_pop 没有释放它。我觉得如果 stack_push 分配了内存,内存管理就变成了这些 Stack 函数的开发者而不是用户的责任。
相反,我想做这样的事情:
void stack_push(Stack *stack, StackElmt *element, void *data)
{
element->data = data;
element->next = stack->top;
stack->top = element;
stack->size++;
}
一个指向 StackElmt 的指针被输入,用户可以自己选择如何分配它。
总结
我的问题是:
- 在 stack_push() 中分配内存但在 stack_pop() 中未释放的代码是否被认为是好的设计?在 stack_pop() 中明确注释用户负责 StackElmt 内存会使设计更好吗?
- 在书中,还有一个叫做“destroy_stack”的函数可以销毁堆栈。在其中,“stack_pop”和一个指针指向的用户定义函数(建议为免费的)针对堆栈中的每个元素运行。从用户的角度来看,这个“销毁”功能是否让负责内存管理的人更清楚?
- 由用户完全分配内存(参见我修改过的 stack_push)还是由程序完全分配更好?
提前谢谢大家!
【问题讨论】:
-
如果 pop 操作在调用时释放了内存,那么如何获取刚刚从堆栈中弹出的数据?
-
如果你问我,这是一个奇怪的设计。
push和pop在这里是不对称的,这不是常规做法。push正在推送一些 data,而pop由于某种原因正在返回整个堆栈元素结构(这就是它无法释放它的原因)。我希望它能够返回数据。 -
这是一个糟糕的设计。但是你的解决方案也不好。
StackElmt类型应该对用户完全隐藏。所以push应该接受数据并且pop应该返回数据(或者你可以有一个top函数来返回数据,在这种情况下pop不返回任何东西,只处理内部簿记)
标签: c memory-management