1

这是释放整个链表的代码

void free_list(RecordType *list)
{
   RecordType *tempNode;        /* temporary Node to hold on the value of previous node */

   while(list != NULL)          /* as long as the listnode doesn't point to null */
   {
       tempNode = list;         /* let tempNode be listNode in order to free the node */
       list = list->next;       /* let list be the next list (iteration) */
       free(tempNode);          /* free the node! */
   }
}

我认为这段代码本身工作正常(?),但我不知道如何检查。我只应用了这个理论(例如# of frees must = to the # of mallocs)

所以这里有一些我想知道的问题......

  1. 这种方法有效吗?
  2. 我需要 malloc tempNode 吗?
  3. 我在 while 循环之前初始化了 tempNode……但是在我释放之后,tempNode 仍然可以工作……我并没有真正理解那部分

我使用的理论:

  1. # of free() == # of malloc()
  2. 您需要一个临时节点来保存当前节点
  3. 让当前节点等于下一个节点
  4. 使用临时节点释放当前节点

如果我的任何理论听起来是错误的,请解释!

谢谢!

4

3 回答 3

2

这种方法有效吗?

是的,假设列表节点都是动态分配的并且之前没有被释放

我需要 malloc tempNode 吗?

您不需要在内部分配任何内存,free_list但所有列表元素必须先前已动态分配。您只能调用free使用malloc(或calloc)分配的内存

我在 while 循环之前初始化了 tempNode……但是在我释放之后,tempNode 仍然可以工作……我并没有真正理解那部分

调用free将内存所有权返回给系统。它可能会选择立即重用此内存,也可能会在一段时间内保持不变。没有什么可以阻止您再次访问内存,但读取或写入它的结果是不确定的。

如果您想让客户端代码更难意外访问已释放的内存,您可以将free_list其指针更改为 NULL

void free_list(RecordType **list)
{
    RecordType *tempNode;
    while(*list != NULL) {
        tempNode = *list;
        list = tempNode->next;
        free(tempNode);
    }
    *list = NULL;
}

如果您还想检查您是否真的释放了所有内存,请考虑使用 valgrind。这将报告任何内存泄漏,并标记某些类型的无效内存访问。

于 2013-02-28T09:28:36.277 回答
1

该方法当然有效 - 但它应该在ingmalloc之前先 d 。free否则它是未定义的行为。

仅当先前已dmalloc() tempNode时才需要。listmalloc()

第三部分是未定义的行为。之后free()数据可能仍然存在,但被标记为被覆盖。你不能依赖节点一旦它是free()d

于 2013-02-28T09:31:09.893 回答
0

检查代码的最佳方法是通过调试器进行交互式跟踪。Linux 上的 KDevelop 中的 Gdb 或 MS Windows 上的 MS Visual Studio 调试器是完美的。我将在此演示中使用后者。

这段代码定义了一个具有三个函数的单向整数列表:ListPush() 将整数添加到列表中,ListPrint() 显示列表内容,ListDestroy() 销毁列表。在 main() 中,我将 3 个整数插入到列表中,打印它们并销毁列表。

#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct Node NODE, *PNODE;
typedef struct Node {
    int item;
    PNODE next;
};
PNODE ListPush(PNODE head, int item) {
    PNODE p;
    PNODE n = (PNODE) malloc(sizeof(NODE));
    if ( !n ) exit(1);
    n->next = 0;
    n->item = item;

    if (!head) {
        head = n;
    }
    else {
        for ( p=head; p->next != 0; p=p->next );
        p->next = n;    
    }
    return head;
}

void ListPrint(PNODE head) {
    PNODE p;
    printf("List contents:\n\n");
    for (p=head; p!=0; p=p->next) {
        printf("%d ", p->item ); 
    }
}

void ListDestroy( PNODE head ) {
    PNODE n, c = head;
    if ( !head ) return; 
    do {
        n = c->next;
        free(c);
        c = n;
    } while (c );

}

int main() {
    int i;
    int a[3] = {1,2,3};
    PNODE head = 0;
    for ( i = 0; i<3; ++i ) {
        head = ListPush(head, a[i]);
    }
    ListPrint(head);
    ListDestroy(head);
    return 0;
}

三张附加图片说明了程序的 2 个阶段(MSVS2012 调试器)。

第一个显示 for() 循环完成后相关本地变量的状态。查看头变量并在树上继续。您可以看到三个节点及其内容:分别为整数 1,2 和 3。

第二张图显示了第一次调用 free() 后 ListDestroy() 中的变量。您可以看到 head 指向已释放的内存(红色圆圈),变量 c 中的指针指向在下一个循环中被销毁的下一个节点。

3次推后

在第一次调用 free() 之后

于 2013-02-28T10:28:03.733 回答