1. 程式人生 > >C指針原理(28)-垃圾回收-內存泄露

C指針原理(28)-垃圾回收-內存泄露

itl imp 申請 eof == main malloc 無法刪除 表示

一、內存泄露

1、正常的鏈表操作

下面程序建立一個10元素的鏈表,輸出它們的節點,每個節點是一個員工的工號和年齡。最後刪除每個節點,釋放列表。

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

#include <stdlib.h>
#include <stdio.h>
//code:[email protected]
//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:[email protected]

//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:[email protected]

//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:[email protected]

//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指針原理(28)-垃圾回收-內存泄露