C指针原理教程之垃圾回收-内存泄露
一、内存泄露
1、正常的链表操作
下面程序建立一个10元素的链表,输出它们的节点,每个节点是一个员工的工号和年龄。最后删除每个节点,释放列表。
dp@dp:~/memorytest%cat1.c #include#include //code:myhaspl@myhaspl.com //author:myhaspl //date:2014-01-10 typedefstructlistnodemynode; structlistnode{ mynode*next; intnumber; intage; }; mynode*addnode(mynode*prevnd,intnumber,intage){ mynode*ndtemp=(mynode*)malloc(sizeof(mynode)); prevnd->next=ndtemp; ndtemp->number=number; ndtemp->age=age; ndtemp->next=NULL; returnndtemp; } mynode*initlist(){ mynode*temp=(mynode*)malloc(sizeof(mynode)); temp->number=0; temp->age=0; temp->next=NULL; returntemp; } intmain(){ mynode*mylist=initlist(); mynode*mytempnd=mylist; inti=0;f悬挂指针 for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } //下面是正常的链表操作 //先输出链表元素 for(mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //然后删除链表中的所有元素 mynode*oldtmpnd; for(mytempnd=mylist->next;mytempnd!=NULL;){ printf("deleteid:%d\n",mytempnd->number); oldtmpnd=mytempnd; mytempnd=mytempnd->next; free(oldtmpnd); } free(mylist); return0; }
下面是程序运行效果
dp@dp:~/memorytest%gcc1.c-omytest dp@dp:~/memorytest%./mytest id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 deleteid:0 deleteid:1 deleteid:2 deleteid:3 deleteid:4 deleteid:5 deleteid:6 deleteid:7 deleteid:8 deleteid:9 dp@dp:~/memorytest%
下面演示了垃圾的形成,这是内存泄露的一种方式,即在链表中,某些节点与链表中的其它节点失去联系,导致无法删除,下面故意让第4个结点的next指针指向null,失去与后面6个元素的联系。
dp@dp:~/memorytest%cat1.c #include#include //code:myhaspl@myhaspl.com //author:myhaspl //date:2014-01-10 typedefstructlistnodemynode; structlistnode{ mynode*next; intnumber; intage; }; mynode*addnode(mynode*prevnd,intnumber,intage){ mynode*ndtemp=(mynode*)malloc(sizeof(mynode)); prevnd->next=ndtemp; ndtemp->number=number; ndtemp->age=age; ndtemp->next=NULL; returnndtemp; } mynode*initlist(){ mynode*temp=(mynode*)malloc(sizeof(mynode)); temp->number=0; temp->age=0; temp->next=NULL; returntemp; } intmain(){ mynode*mylist=initlist(); mynode*mytempnd=mylist; inti=0; for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } //下面是正常的链表操作 //先输出链表元素 for(mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //然后删除链表中的所有元素 for(mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("deleteid:%d\n",mytempnd->number); free(mytempnd); } free(mylist); //下面是形成内存泄露第一种情况-垃圾的演示 //生成并输出链表,这个与前面相同 mylist=initlist(); mytempnd=mylist; i=0; for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } for(mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //删除链表,我们故意留下后面6个链表节点无法删除,导致后面6个链表节点形成垃圾 intj=0; for(mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ if(++j>3){ mytempnd->next=NULL; break; } } for(mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("deleteid:%d\n",mytempnd->number); free(mytempnd); j++; } return0; }
下面是程序运行效果
dp@dp:~/memorytest%gcc1.c-omytest dp@dp:~/memorytest%./mytest id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 deleteid:0 deleteid:1 deleteid:2 deleteid:3 deleteid:4 deleteid:5 deleteid:6 deleteid:7 deleteid:8 deleteid:9 id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 deleteid:0 deleteid:1 deleteid:2 deleteid:3 dp@dp:~/memorytest%
3、悬挂指针
一个指针不为空,但是指向一个无效的地址或耒知对象的地址,则这样的指针称为悬挂指针。
dp@dp:~/memorytest%cat2.c #include#include //code:myhaspl@myhaspl.com //author:myhaspl //date:2014-01-10 typedefstructlistnodemynode; structlistnode{ mynode*next; intnumber; intage; }; mynode*addnode(mynode*prevnd,intnumber,intage){ mynode*ndtemp=(mynode*)malloc(sizeof(mynode)); prevnd->next=ndtemp; ndtemp->number=number; ndtemp->age=age; ndtemp->next=NULL; returnndtemp; } mynode*initlist(){ mynode*temp=(mynode*)malloc(sizeof(mynode)); temp->number=0; temp->age=0; temp->next=NULL; returntemp; } intmain(){ mynode*mylist=initlist(); mynode*mytempnd=mylist; inti=0; for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } //下面是正常的链表操作 //先输出链表元素 for(mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //然后删除链表中的所有元素 mynode*oldtmpnd; for(mytempnd=mylist->next;mytempnd!=NULL;){ printf("deleteid:%d\n",mytempnd->number); oldtmpnd=mytempnd; mytempnd=mytempnd->next; free(oldtmpnd); } free(mylist); //下面是形成内存泄露第二种情况-悬挂指针的演示 //生成并输出链表,这个与前面相同 mylist=initlist(); mytempnd=mylist; i=0; for(i=0;i<10;i++){ mytempnd=addnode(mytempnd,i,20+i); } for(mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d\n",mytempnd->number,mytempnd->age); } //我们故意删除链表后面的4个节点,但是让第6个元素的next指向的地址无效, //仍指向已经删除的第7个节点,导致悬挂指针 printf("-------------------------\n"); intj=0; for(mytempnd=mylist->next;mytempnd!=NULL;){ oldtmpnd=mytempnd; mytempnd=mytempnd->next; if(++j>6){ printf("deleteid:%d\n",oldtmpnd->number); free(oldtmpnd); } } return0; }
执行程序
dp@dp:~/memorytest%gcc2.c-omytest dp@dp:~/memorytest%./mytest id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 deleteid:0 deleteid:1 deleteid:2 deleteid:3 deleteid:4 deleteid:5 deleteid:6 deleteid:7 deleteid:8 deleteid:9 id:0,age:20 id:1,age:21 id:2,age:22 id:3,age:23 id:4,age:24 id:5,age:25 id:6,age:26 id:7,age:27 id:8,age:28 id:9,age:29 deleteid:6 deleteid:7 deleteid:8 deleteid:9
但是注意free函数表示释放,这个释放指的是把这段内存标记成可用状态,或者说,没有人在用这段内存了,也就是意味着如果这段内存如果没有被操作系统重新使用,里面的数据还存在,如果被操作系统分配给其它程序或本程序的其它内存块申请之用,则数据会被清空。
3、下面是形成内存泄露第三种情况-共享的演示,多个指针指向同一个内存,这个内存因为某个指针不再使用的原因删除,导致其它指针指向一个无效地址
dp@dp:~/memorytest%cat2.c #include#include //code:myhaspl@myhaspl.com //author:myhaspl //date:2014-01-10 typedefstructlistnodemynode; structlistnode{ mynode*next; char*data; intnumber; intage; }; mynode*addnode(mynode*prevnd,intnumber,intage,char*data){ mynode*ndtemp=(mynode*)malloc(sizeof(mynode)); prevnd->next=ndtemp; ndtemp->number=number; ndtemp->age=age; ndtemp->data=data; ndtemp->next=NULL; returnndtemp; } mynode*initlist(){ mynode*temp=(mynode*)malloc(sizeof(mynode)); temp->number=0; temp->age=0; temp->data=NULL; temp->next=NULL; returntemp; } intmain(){ //下面是形成内存泄露第三种情况-共享的演示,多个指针指向同一个内存,这个内存因为某个指针不再使用的原因删除, //生成并输出链表,生成1个链表(共3个元素),元素的data都指向同一个内存块 mynode*mylist=initlist(); mynode*mytempnd=mylist; char*mydata=(char*)malloc(100); constchar*strsrc="helloworld"; strcpy(mydata,strsrc); inti=0; for(i=0;i<3;i++){ mytempnd=addnode(mytempnd,i,20+i,mydata); } for(mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){ printf("id:%d,age:%d,data:%s\n",mytempnd->number,mytempnd->age,mytempnd->data); } //下面将导致共享的内存释放,但仍有2个结点指向这个内存,这将导致内存泄露 //我们故意删除最后一个节点,并释放最后一个结点的data指针指向的内存 printf("-------------------------\n"); mynode*oldtmpnd; for(mytempnd=mylist->next;mytempnd!=NULL;){ oldtmpnd=mytempnd; mytempnd=mytempnd->next; if(mytempnd==NULL){ printf("deleteid:%d\n",oldtmpnd->number); free(oldtmpnd->data); free(oldtmpnd); } } return0; }
执行程序:
dp@dp:~/memorytest%gcc2.c-omytest 2.c:Infunction'main': 2.c:37:warning:incompatibleimplicitdeclarationofbuilt-infunction'strcpy' dp@dp:~/memorytest%./mytest id:0,age:20,data:helloworld id:1,age:21,data:helloworld id:2,age:22,data:helloworld deleteid:2 dp@dp:~/memorytest%
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。