关于free的使用疑惑

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include "mainc26.h"
 5 struct TelPhone{
 6     char name[20];
 7     char TelNumber[20];
 8     struct TelPhone* next;
 9 };
10 int mainc26()
11 {
12 
13 
14     setbuf(stdout, NULL);
15     //fflush(stdout);
16     struct TelPhone *head = NULL;
17     struct TelPhone *pre,*current;
18     char input[20];
19     printf("请输入联系人的姓名:\n");
20     fflush(stdout);
21     while(gets(input) != NULL && input[0] != '\0')
22     {
23         current = (struct TelPhone*)malloc(sizeof(struct TelPhone));
24         if(head == NULL)
25             head = current;
26         else
27             pre->next = current;
28         current->next = NULL;
29         strcpy(current->name,input);
30         printf("请输入联系人的电话号码:\n");
31         scanf("%s",current->TelNumber);
32         while(getchar() != '\n')
33             continue;
34         printf("请输入下一个联系人(空行则退出):\n");
35         pre = current;
36     }
37     if(head == NULL)
38         printf("电话里面没有储存任何数据:");
39     else
40         puts("通讯录:");
41     current = head;
42     while(current != NULL)
43     {
44         printf("%s:%s\n",current->name,current->TelNumber);
45         current = current->next;
46     }
47     current = head;
48     int n=0;
49     while(current != NULL)
50     {
51         n++;
52         printf("this is %d time \n",n);
53         free(current);
54         current=NULL;
55         printf("cur.name %s   ,",current->name);
56         printf("cur.teln %s   ,",current->TelNumber);
57 //        printf("cur.name %p   ,",current->next);
58         printf("\n");
59         current = current->next;
60     }
61     return 0;
62 }

在 line 53中 使用free(current) ,这里似乎是将current的内存释放,然后实际上,这里的释放后,其内存信息已经存在,

如果将line 54的current=null,注释,该程序仍能正确运行,并通过该链表将内存释放掉,而实际上这种问题时错误的。

 

通过百度,我查到

问题如下:

 1 代码如下:
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4  
 5 struct test 
 6 {
 7 int a;
 8 struct test *next;
 9 };
10 int main()
11 {
12 struct test test0={10};
13 struct test *test1 = (struct test *)malloc(sizeof(struct test));
14 test1->a=20;
15 test1->next = &test0;
16 free(test1);
17 printf("%d %d",test1->a,(*test1->next).a); 
18 
19 }
20 输出test1->a为0  ,(*test1->next).a为10
21  
22 说明结构体里的变量a已经被free释放掉了,而test1的指针next却还可以被访问
View Code

解答如下

free函数,实际上做的事情不是真正的释放内存。
首先你要清楚,内存是由操作系统来管理的(操作包括分配、释放等)。
系统中的内存在c语言分配内存机制上被分为很多个块,c的底层代码用数据结构chunk来表示。chunk中有一个标志位,用来表示该内存块是否为待分配或者已分配状态。每一次调用malloc,这个标志位会被设置1(好像是1,记不太清楚了),调用free时被设置为0. 操作系统的内存管理机制会根据这个值来分配和释放内存。
也就是说调用free的时候,只是设置了这个标志位(当然还做了其他事,就你这个问题而言,只讨论这个),而内存还原封不动的在那里。所以,当你在系统真正释放这个内存之前再次访问这个地址,你会得到你想要的结果。
说明,“输出test1->a为0”,这个的原因可能是free的时候,设置chunk块的标志位时,覆盖了a的值。chunk数据结构中,第一个字节的前8位是标志位,后面还有24位也有各自的用处。具体是什么导致a的值为0的,你有兴趣的话,你可以自己去研究。可以去阅读linux的glibc源码。
"(*test1->next).a为10",就简单了。next偏移struct test所占内存的“头(head)”距离较远,free的时候的一些设置值的操作没有影响到,能访问到这个指针的值,并且test0还在函数栈中完整保留,自然就能访问到了。

P.S c/C++的malloc/free和new/delete都有这个特性,所以编程的时候要养成一个良好习惯,在调用free和delete的时候要将指针赋值为NULL,如:
free(ptr);
ptr=NULL;
或者
delete ptr;
ptr=NULL;



所以这里和回答的问题比较相符,
实际上free(current)以后,其内存的实际内容 并没有被释放,仍然可以使用,但这样是应该,
应该讲内存释放后的变量赋值为NULL.
那么单项链表的内存该如何释放呢??

可以参考如下的代码,将其释放
 1     //释放内存
 2     struct TelPhone * temp;
 3     while(current != NULL)
 4     {
 5         n++;
 6 
 7         printf("this is %d time \n",n);
 8         printf("cur.name %s   ,",current->name);
 9         printf("cur.teln %s   ,",current->TelNumber);
10         printf("cur.name %p   ,",current->next);
11         printf("\n");
12 
13         temp=current;
14         current=current->next;
15         free(temp);
16         temp=NULL;
17     }
View Code

 



posted @ 2016-07-02 17:18  九点人  阅读(469)  评论(0编辑  收藏  举报