C/C++知识点之C指针原理(28)-垃圾回收-内存泄露
小标 2019-02-19 来源 : 阅读 1067 评论 0

摘要:本文主要向大家介绍了 C/C++知识点之C指针原理(28)-垃圾回收-内存泄露,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

本文主要向大家介绍了 C/C++知识点之C指针原理(28)-垃圾回收-内存泄露,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

C/C++知识点之C指针原理(28)-垃圾回收-内存泄露

一、内存泄露


1、正常的链表操作


下面程序建立一个10元素的链表,输出它们的节点,每个节点是一个员工的工号和年龄。最后删除每个节点,释放列表。


dp@dp:~/memorytest % cat 1.c


#include <stdlib.h>
#include <stdio.h>
//code:myhaspl@myhaspl.com
//author:myhaspl
//date:2014-01-10
typedef struct listnode mynode; 
struct listnode{
    mynode *next;
    int number;
    int age;
    };
mynode *addnode(mynode *prevnd,int number,int age){
    mynode *ndtemp=(mynode*)malloc(sizeof(mynode));
    prevnd->next=ndtemp;
    ndtemp->number=number;
    ndtemp->age=age;
    ndtemp->next=NULL;
    return ndtemp;
}
mynode *initlist(){
    mynode *temp=(mynode*)malloc(sizeof(mynode));   
    temp->number=0;
    temp->age=0;
    temp->next=NULL;
    return temp;
}
int  main(){
    mynode *mylist=initlist();
    mynode *mytempnd=mylist;
    int i=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("delete id:%d\n",mytempnd->number);
        oldtmpnd=mytempnd;
        mytempnd=mytempnd->next;
        free(oldtmpnd);
    }
    free(mylist);
        return 0;   
}


下面是程序运行效果


dp@dp:~/memorytest % gcc 1.c -o mytest


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


delete id:0


delete id:1


delete id:2


delete id:3


delete id:4


delete id:5


delete id:6


delete id:7


delete id:8


delete id:9


dp@dp:~/memorytest % 


下面演示了垃圾的形成,这是内存泄露的一种方式,即在链表中,某些节点与链表中的其它节点失去联系,导致无法删除,下面故意让第4个结点的next指针指向null,失去与后面6个元素的联系。


dp@dp:~/memorytest % cat 1.c



#include <stdlib.h>

#include <stdio.h>

//code:myhaspl@myhaspl.com

//author:myhaspl

//date:2014-01-10

typedef struct listnode mynode; 

struct listnode{

mynode *next;

int number;

int age;

};

mynode *addnode(mynode *prevnd,int number,int age){

mynode *ndtemp=(mynode*)malloc(sizeof(mynode));

prevnd->next=ndtemp;

ndtemp->number=number;

ndtemp->age=age;

ndtemp->next=NULL;

return ndtemp;

}

mynode *initlist(){

mynode *temp=(mynode*)malloc(sizeof(mynode));

temp->number=0;

temp->age=0;

temp->next=NULL;

return temp;

}

int  main(){

mynode *mylist=initlist();

mynode *mytempnd=mylist;

int 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);

}

//然后删除链表中的所有元素

for (mytempnd=mylist->next;mytempnd!=NULL;mytempnd=mytempnd->next){

printf("delete id:%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个链表节点形成垃圾

int j=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("delete id:%d\n",mytempnd->number);

free(mytempnd);

j++; 

}

        return 0;

}


下面是程序运行效果


dp@dp:~/memorytest % gcc 1.c -o mytest


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


delete id:0


delete id:1


delete id:2


delete id:3


delete id:4


delete id:5


delete id:6


delete id:7


delete id:8


delete id: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


delete id:0


delete id:1


delete id:2


delete id:3


dp@dp:~/memorytest %


3、悬挂指针


一个指针不为空,但是指向一个无效的地址或耒知对象的地址,则这样的指针称为悬挂指针。



dp@dp:~/memorytest % cat 2.c

#include <stdio.h>

#include <stdlib.h>

//code:myhaspl@myhaspl.com

//author:myhaspl

//date:2014-01-10

typedef struct listnode mynode;

struct listnode{

mynode *next;

int number;

int age;

};

mynode *addnode(mynode *prevnd,int number,int age){

mynode *ndtemp=(mynode*)malloc(sizeof(mynode));

prevnd->next=ndtemp;

ndtemp->number=number;

ndtemp->age=age;

ndtemp->next=NULL;

return ndtemp;

}

mynode *initlist(){

mynode *temp=(mynode*)malloc(sizeof(mynode));

temp->number=0;

temp->age=0;

temp->next=NULL;

return temp;

}

int  main(){

mynode *mylist=initlist();

mynode *mytempnd=mylist;

int 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);

}

//然后删除链表中的所有元素

mynode* oldtmpnd;

for (mytempnd=mylist->next;mytempnd!=NULL;){

printf("delete id:%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");

int j=0;

for (mytempnd=mylist->next;mytempnd!=NULL;){

oldtmpnd=mytempnd;

mytempnd=mytempnd->next;

if (++j>6){

printf("delete id:%d\n",oldtmpnd->number);

free(oldtmpnd);

}

}

        return 0;

}


执行程序


dp@dp:~/memorytest % gcc 2.c -o mytest


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


delete id:0


delete id:1


delete id:2


delete id:3


delete id:4


delete id:5


delete id:6


delete id:7


delete id:8


delete id: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




delete id:6


delete id:7


delete id:8


delete id:9


但是注意free函数表示释放,这个释放指的是把这段内存标记成可用状态,或者说,没有人在用这段内存了,也就是意味着如果这段内存如果没有被操作系统重新使用,里面的数据还存在,如果被操作系统分配给其它程序或本程序的其它内存块申请之用,则数据会被清空。


3、下面是形成内存泄露第三种情况-共享的演示,多个指针指向同一个内存,这个内存因为某个指针不再使用的原因删除,导致其它指针指向一个无效地址


dp@dp:~/memorytest % cat 2.c



#include <stdio.h>

#include <stdlib.h>

//code:myhaspl@myhaspl.com

//author:myhaspl

//date:2014-01-10

typedef struct listnode mynode;

struct listnode{

mynode *next;

char *data;

int number;

int age;

};

mynode *addnode(mynode *prevnd,int number,int age,char *data){

mynode *ndtemp=(mynode*)malloc(sizeof(mynode));

prevnd->next=ndtemp;

ndtemp->number=number;

ndtemp->age=age;

ndtemp->data=data;

ndtemp->next=NULL;

return ndtemp;

}

mynode *initlist(){

mynode *temp=(mynode*)malloc(sizeof(mynode));

temp->number=0;

temp->age=0;

temp->data=NULL;

temp->next=NULL;

return temp;

}

int  main(){

        //下面是形成内存泄露第三种情况-共享的演示,多个指针指向同一个内存,这个内存因为某个指针不再使用的原因删除,

//生成并输出链表,生成1个链表(共3个元素),元素的data都指向同一个内存块

mynode *mylist=initlist();

mynode *mytempnd=mylist;

char *mydata=(char *)malloc(100);

const char *strsrc="helloworld";

strcpy(mydata,strsrc);

int i=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("delete id:%d\n",oldtmpnd->number);

free(oldtmpnd->data);

free(oldtmpnd);

}

}

        return 0;

}


执行程序:


dp@dp:~/memorytest % gcc 2.c -o mytest


2.c: In function 'main':


2.c:37: warning: incompatible implicit declaration of built-in function 'strcpy'


dp@dp:~/memorytest % ./mytest


id:0,age:20,data:helloworld


id:1,age:21,data:helloworld


id:2,age:22,data:helloworld




delete id:2


dp@dp:~/memorytest % 

   

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C/C+频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程