程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 高質量的C代碼.釋放內存

高質量的C代碼.釋放內存

編輯:關於C語言

  未經許可,不的轉載
  版權歸屬高雷個人
  聯系方式:
  email:[email protected]
  qq:38929568

由於本人剛剛編寫C程序不久,文章中不當的地方難免會有,望大家批評指正,我會第一時間修改!

  最近搞MTK游戲開發,使用的是C語言,所以想研究一下C語言的開發情況,通過論壇,或者搜索到一些高手的文章,給我的啟示不小!結合以前的Java經驗,想總結一下,高手都是如何寫程序的...

  我的文章不會講述一個C語言學習的過程,也不會面面俱到講述C語言,我只針對學習過C語言,或者有一定編程基礎,在寫代碼的時候總是不自信地想知道別人是如何編寫的!

  我希望通過閱讀本文,能夠使初級程序員迅速成長為高級程序員!

  1.如何釋放內存

  很簡單free();就ok啦!

  C語言中,malloc,realloc,calloc,strdup等等都是動態從堆裡面分配的內存,他不會自動釋放。在這裡需要記錄分配的地址,以便以後釋放。如果不進行釋放,會造成內存洩漏。在堆內存申請的內存是需要程序員管理的,系統不會主動回收,可以通過free()函數回收。通常的商業代碼都有很多指針,或者指針的指針,結構體裡包含指針類型的成員,那麼這些指針該如何管理,才不至於出錯呢?

  例如 Role *pRole = (Role *)malloc( sizeof(Role) );

  釋放指針

  free( pRole );

  pRole = NULL;

釋放指針後,將指針指回0點,如果你覺得每次都要寫2行代碼太麻煩了,可以定一個宏
 

/*
*	釋放指針類型數據,直接使用內存指針變量
*/
#define FREE(X)						\
do{								\
if( (X) != NULL )			\
{							\
free( (void *)(X) );	\
(X)=NULL;				\
}							\
}while(0)

 

如果行用一個函數來釋放並且達到同樣的目的該如何寫呢?

 

view plaincopy to clipboardprint?
  1. //釋放指針類型數據
  2. void freePointer(void *p)
  3. {
  4. if( p != NULL )
  5. {
  6. free( p );
  7. p = NULL;
  8. }
  9. }

//釋放指針類型數據
void freePointer(void *p)
{
if( p != NULL )
{
free( p );
p = NULL;
}
}

 

這麼寫是不行的,因為指針p是通過copy方式將實參的值copy過來,

free( p ); 沒問題,可以把指針p所指的內存釋放,但取無法把指針指向NULL,這是因為形參的地址和實參的地址是不同的!

 

view plaincopy to clipboardprint?
  1. //釋放指針類型數據
  2. void freePointer(void **p)
  3. {
  4. if( *p != NULL )
  5. {
  6. free( *p );
  7. *p = NULL;
  8. }
  9. }

//釋放指針類型數據
void freePointer(void **p)
{
if( *p != NULL )
{
free( *p );
*p = NULL;
}
}

 

這樣修改就可以了,但這要求實參數是一個指針的地址

使用的時候要這麼用

freePointer( (void *)(&pRole) );

這樣用著依然不爽,強制類型轉換有些編譯器是必須的,比如我用的,

基本不是,取指針地址還是必須的!總之給人不直觀,不清爽的感覺,

如果換成

FREE( pRole );

就好多了!

  1.1如果釋放一個帶有指針的結構體指針

 

view plaincopy to clipboardprint?
  1. //角色數據類型
  2.  
  3. typedef struct
  4. {
  5.   char* name; //動作文件的名字
  6. }ACT; //動畫
  7.  
  8.  
  9. typedef struct
  10. {
  11.   ACT* body; //身體動作數據
  12. }Role;

//角色數據類型
typedef struct
{
  char* name; //動作文件的名字
}ACT; //動畫
typedef struct
{
  ACT* body; //身體動作數據
}Role;

 

創建角色對象,我想通過一個方法

 

view plaincopy to clipboardprint?
  1. // 創建 角色數據對象
  2. Role* creatRole( const char* roleName, uint8 weaponId );
  3. // 回收 角色數據對象
  4. void destroyRole( Role *role);

// 創建 角色數據對象
Role* creatRole( const char* roleName, uint8 weaponId );
// 回收 角色數據對象
void destroyRole( Role *role);

 

那麼創建的時候確實可以得到一個角色的指針

Role *pRole =creatRole( "hero", 0 );

釋放的時候如果想達到調用

destroyRole(pRole );

後,pRole 指向NULL,該如何做呢?

通過freePointer()方法給我們的教訓可以知道,

 

view plaincopy to clipboardprint?
  1. /* 回收 角色數據對象 */
  2. void destroyRole( Role *role )
  3. {
  4.   if( role == NULL )
  5.   return;
  6.  
  7.   destroyAct( role->body );//是否結構體內的指針,有幾個就要釋放幾個
  8.    free( role );
  9.  
  10.   role = NULL;
  11. }

/* 回收 角色數據對象 */
void destroyRole( Role *role )
{
  if( role == NULL )
  return;
  destroyAct( role->body );//是否結構體內的指針,有幾個就要釋放幾個
   free( role );
  role = NULL;
}

 

其中的role = NULL;是不能把實參pRole 指向NULL的!

如果我們向前面提到那樣使用宏,或者獲取指針地址的形式似乎可以解決,但其實沒必要那麼麻煩,通常的做法是手動指向NULL

destroyRole(pRole );

pRole = NULL;

為什麼要有pRole = NULL;這句呢?因為最上層的結構體對象通常都是需要程序知道是否

為空,或者非空,另外指回原點,也對調試有好處,單獨free()對象,在調試的時候是看不出來的!

另外還要提到一點

 

view plaincopy to clipboardprint?
  1. Role* creatRole( const char* roleName, uint8 weaponId )
  2.  
  3. {
  4.  
  5. Role role;
  6.  
  7. role.body= (ACT*)malloc( sizeof(ACT) );
  8.  
  9. return &role;
  10.  
  11. }

Role* creatRole( const char* roleName, uint8 weaponId )
{
Role role;
role.body= (ACT*)malloc( sizeof(ACT) );
return &role;
}

 

這個方法是絕對不可取的,因為role是函數內部的臨時變量,在函數結束的時候會被系統回收的,隨意&role這個地方的數據將被系統重新使用。

在C語言編程中並不是所有指針都需要指回NULL的,如果你願意都指回NULL更好,但至少應該把一組指針的源頭指回NULL,這才能防止程序出錯,另外就是把源頭指回NULL之前要確保該指針下面的全部指針都已經被回收了!否則就內存洩漏了!

PS.未經許可 不得轉載!

本文出自 “鍵碼視窗” 博客,謝絕轉載!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved