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