C指針原理教程之垃圾回收-內(nèi)存泄露
一、內(nèi)存泄露
1、正常的鏈表操作
下面程序建立一個(gè)10元素的鏈表,輸出它們的節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)是一個(gè)員工的工號(hào)和年齡。最后刪除每個(gè)節(jié)點(diǎn),釋放列表。
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;  
}
下面是程序運(yùn)行效果
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 %
下面演示了垃圾的形成,這是內(nèi)存泄露的一種方式,即在鏈表中,某些節(jié)點(diǎn)與鏈表中的其它節(jié)點(diǎn)失去聯(lián)系,導(dǎo)致無(wú)法刪除,下面故意讓第4個(gè)結(jié)點(diǎn)的next指針指向null,失去與后面6個(gè)元素的聯(lián)系。
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);
//下面是形成內(nèi)存泄露第一種情況-垃圾的演示
//生成并輸出鏈表,這個(gè)與前面相同
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個(gè)鏈表節(jié)點(diǎn)無(wú)法刪除,導(dǎo)致后面6個(gè)鏈表節(jié)點(diǎn)形成垃圾
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;
}
下面是程序運(yùn)行效果
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、懸掛指針
一個(gè)指針不為空,但是指向一個(gè)無(wú)效的地址或耒知對(duì)象的地址,則這樣的指針?lè)Q為懸掛指針。
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);
//下面是形成內(nèi)存泄露第二種情況-懸掛指針的演示
//生成并輸出鏈表,這個(gè)與前面相同
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個(gè)節(jié)點(diǎn),但是讓第6個(gè)元素的next指向的地址無(wú)效,
//仍指向已經(jīng)刪除的第7個(gè)節(jié)點(diǎn),導(dǎo)致懸掛指針
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;
}
執(zhí)行程序
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函數(shù)表示釋放,這個(gè)釋放指的是把這段內(nèi)存標(biāo)記成可用狀態(tài),或者說(shuō),沒(méi)有人在用這段內(nèi)存了,也就是意味著如果這段內(nèi)存如果沒(méi)有被操作系統(tǒng)重新使用,里面的數(shù)據(jù)還存在,如果被操作系統(tǒng)分配給其它程序或本程序的其它內(nèi)存塊申請(qǐng)之用,則數(shù)據(jù)會(huì)被清空。
3、下面是形成內(nèi)存泄露第三種情況-共享的演示,多個(gè)指針指向同一個(gè)內(nèi)存,這個(gè)內(nèi)存因?yàn)槟硞€(gè)指針不再使用的原因刪除,導(dǎo)致其它指針指向一個(gè)無(wú)效地址
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(){
    //下面是形成內(nèi)存泄露第三種情況-共享的演示,多個(gè)指針指向同一個(gè)內(nèi)存,這個(gè)內(nèi)存因?yàn)槟硞€(gè)指針不再使用的原因刪除,
//生成并輸出鏈表,生成1個(gè)鏈表(共3個(gè)元素),元素的data都指向同一個(gè)內(nèi)存塊
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);
    }
//下面將導(dǎo)致共享的內(nèi)存釋放,但仍有2個(gè)結(jié)點(diǎn)指向這個(gè)內(nèi)存,這將導(dǎo)致內(nèi)存泄露
//我們故意刪除最后一個(gè)節(jié)點(diǎn),并釋放最后一個(gè)結(jié)點(diǎn)的data指針指向的內(nèi)存
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;
}
執(zhí)行程序:
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++中各種可調(diào)用對(duì)象深入講解
欄 目:C語(yǔ)言
下一篇:C++類(lèi)中的特殊成員函數(shù)示例詳解
本文標(biāo)題:C指針原理教程之垃圾回收-內(nèi)存泄露
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/459.html
您可能感興趣的文章
- 01-10深入理解數(shù)組指針與指針數(shù)組的區(qū)別
 - 01-10基于C++輸出指針自增(++)運(yùn)算的示例分析
 - 01-10解析sizeof, strlen, 指針以及數(shù)組作為函數(shù)參數(shù)的應(yīng)用
 - 01-10探討C++中數(shù)組名與指針的用法比較分析
 - 01-10深入理解雙指針的兩種用法
 - 01-10libxml教程(圖文詳解)
 - 01-10C語(yǔ)言數(shù)組指針的小例子
 - 01-10基于SVN源碼服務(wù)器搭建(詳細(xì)教程分析)
 - 01-10解析如何用指針實(shí)現(xiàn)整型數(shù)據(jù)的加法
 - 01-10深入const int *p與int * const p的區(qū)別詳解(常量指針與指向常量的指
 


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
 - 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
 - 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
 - 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
 - 5c語(yǔ)言計(jì)算三角形面積代碼
 - 6什么是 WSH(腳本宿主)的詳細(xì)解釋
 - 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
 - 8正則表達(dá)式匹配各種特殊字符
 - 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
 - 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
 
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
 - 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
 - 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
 - 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
 - 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
 - 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
 - 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
 - 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
 - 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
 - 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
 
隨機(jī)閱讀
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
 - 01-10C#中split用法實(shí)例總結(jié)
 - 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
 - 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
 - 04-02jquery與jsp,用jquery
 - 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
 - 01-10delphi制作wav文件的方法
 - 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
 - 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
 - 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
 


