如何检查free(节点)是否有效

时间:2013-02-28 09:26:48

标签: c linked-list free

以下是释放整个链表的代码

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! */
   }
}

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

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

  1. 此方法有效吗?
  2. 我需要malloc tempNode吗?
  3. 我在while循环之前初始化了tempNode ...但是在我释放之后,tempNode仍然有效......我真的没有得到那个部分
  4. 我使用的理论:

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

      如果我的理论听起来不对,请解释一下!

      谢谢!

3 个答案:

答案 0 :(得分: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。这将报告任何内存泄漏,并标记某些类型的无效内存访问。

答案 1 :(得分:1)

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

仅当malloc()之前已tempNode时,您才需要list malloc()

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

,您就不能依赖该节点

答案 2 :(得分: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;
}

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

第一个显示for()循环结束后的相关局部变量的状态。查看head变量并继续进行树。您可以看到三个节点及其内容:分别为整数1,2和3。

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

After 3 pushes

After first call to free()