我试图找到一些明确解释的教程,在释放内存时需要记住的是什么。但是我找不到这样的东西。任何人都可以让我知道程序员在释放C中的内存时应该记住的主要内容。我目前正在处理链表。有些情况下新的链表使用2个或更多现有链接列表创建。例如:
list l1;
list l2
list l3 = list_append(l1,l2)
list l4 = list_append(l3,l1)
list l5 = list_append(l3,l4)
释放内存时我必须遵循的解除分配顺序是什么?
这里list_append是返回列表副本的函数。
答案 0 :(得分:3)
使用malloc
/ free
系列函数时,有两条规则需要遵守。
free
malloc
家庭分配器返回的有效内存,释放它会使其无效(因此双重释放是一个错误,因为释放的内存不是从malloc获得的)。以下是重要部分:分配器提供 no 工具来帮助您遵守这些规则。
你必须自己管理它。这意味着您必须安排程序的逻辑,以确保始终遵循这些规则。这是c,你肩负着大量乏味而复杂的责任。
让我建议一些相当安全的模式:
在同一上下文中分配和释放
//...
{
SomeData *p = malloc(sizeof SomeData);
if (!p) { /* handle failure to allocate */ }
// Initialize p
// use p various ways
// free any blocks allocated and assigned to members of p
free p;
}
//...
在这里你知道数据p指向的是一次分配并释放一次,只在两者之间使用。如果初始化和释放SomeData的内容非常重要,那么你应该将它们包装成几个函数,这样就可以减少到
//...
{
SomeData *p = NewSomeData(i,f,"name"/*,...*/); // this handles initialization
if (!p) { /* handle failure to allocate */ }
// use p various ways
ReleaseSomeData(p) // this handles freeing any blocks
// allocated and assigned to members of p
}
//...
将此称为“范围所有权”。您会注意到它与本地自动变量没有太大区别,并且只提供了一些自动无法使用的选项 变量
调用第二个选项“Structure Ownership”:此处删除已分配块的责任将移交给更大的结构:
List L = NewList();
//...
while (something) {
// ...
Node n= NewNode(nodename);
if (!n) { /* handle failure to allocate */ }
ListAdd(L,n); // <=== Here the list takes ownership of the
// node and you should only access the node
// through the list.
n = NULL; // This is not a memory leak because L knows where the new block is, and
// deleting the knowledge outside of L prevents you from breaking the
// "access only through the structure" constraint.
//...
}
// Later
RemoveListNode(L,key); // <== This routine manages the deletion of one node
// found using key. This is why keeping a separate copy
// of n to access the node would have been bad (because
// your separate copy won't get notified that the block
// no longer valid).
// much later
ReleaseList(L); // <== Takes care of deleting all remaining nodes
鉴于您有一个包含要添加和删除的节点的列表,您可能会考虑结构所有权模式,因此请记住:一旦将节点提供给仅 的结构 em>通过结构访问它。
答案 1 :(得分:2)
这个问题一般没什么意义,唯一合理的答案似乎很明显:
第二个要求可以通过在解除分配后将指针设置为NULL或零来辅助,但指针可以保存在其他地方并不是万无一失。
第三个要求在复杂数据结构中尤其是一个问题,其中分配的内存可能包含自身包含指向已分配内存的指针的结构。在释放更高级别的结构之前,您当然需要解除分配这些内容。
答案 2 :(得分:2)
任何人都可以告诉我这是什么 程序员的主要事情 在解除分配时应该记住 C中的记忆。
基本原则非常简单:使用* alloc系列函数分配的任何内存,包括malloc
,calloc
或realloc
,都必须通过对{{{{}}的相应调用来解除分配。 1}}。
将指针(内存地址)传递给free()
时,请记住,您可以传递给free()
的仅有效内存地址是以前返回的内存地址通过其中一个* alloc函数。一旦将内存地址传递给free()
,该内存地址就不再有效,不能用于任何其他目的。
答案 3 :(得分:1)
第一个原则是:
无论你分配什么(使用calloc / malloc)你最终需要自由。
在你的情况下,如果列表在每个追加上深度复制,我看不出有什么问题。您需要单独释放每个列表。
答案 4 :(得分:0)
使用valgrind(1)在您的特定情况下向您显示终止时仍存在的对象,然后修改您的代码以确保释放不必要的对象。
答案 5 :(得分:0)
最好的答案是一个问题..为什么你用C编写代码而不是使用更高级别的语言和更好的内存管理?