关于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却还可以被访问
解答如下
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 }