一、懸垂指針
當所指向的對象被釋放或者收回,但是對該指針沒有作任何的修改,以至於該指針仍舊指向已經回收的內存地址,此情況下該指針便稱懸垂指針(也叫迷途指針)。若操作系統將這部分已經釋放的內存重新分配給另外一個進程,而原來的程序重新引用現在的迷途指針,則將產生無法預料的後果。因爲此時迷途指針所指向的內存現在包含的已經完全 是不同的數據。通常來說,若原來的程序繼續往迷途指針所指向的內存地址寫入數據,這些和原來程序不相關的數據將被損壞,進而導致不可預料的程序錯誤。這種類型的程序錯誤,不容易找到問題的原因,通常會導致段錯誤(Linux系統中)和一般保護錯誤(Windows系統中)。如果操作系統的內存分配器將已經被覆蓋的數據區域再分配,就可能會影響系統的穩定性。
某些編程語言允許未初始化的指針的存在,而這類指針即爲野指針。野指針所導致的錯誤和迷途指針非常相似,但野指針的問題更容易被發現。
二、懸垂指針的成因
在許多編程語言中(比如C),顯示地從內存中刪除一個對象或者返回時通過銷燬棧幀,並不會改變相關的指針的值。該指針仍舊指向內存中相同的位置,即使引用已經被刪除,現在可能已經挪作他用。
一個簡單的例子:
{
char *dp = NULL;
/* ... */
{
char c;
dp = &c;
} /* c falls out of scope *//* dp is now a dangling pointer */
}
上述問題的解決方法是在該部分程序退出之前立即給CP賦0值(NULL)。另一個辦法是保證CP在沒有初始化之前,將不再被使用。
迷途指針經常出現在混雜使用malloc() 和 free() 庫調用: 當指針指向的內存釋放了,這時該指針就是迷途的。和前面的例子一樣,一個避免這個錯誤的方法是在釋放它的引用後將該指針的值重置爲NULL,如下所示:
#include <stdlib.h>
{
char *cp =malloc ( A_CONST );
/* ... */
free ( cp); /* cp now becomes a danglingpointer */
cp = NULL; /* cp is no longer dangling */
/* ... */
}
有個常見的錯誤是當返回一個基於棧分配的局部變量的地址時,一旦調用的函數返回,分配給這些變量的空間將被回收,此時它們擁有的是"垃圾值"。
int * func ( void )
{
int num = 1234;
/* ... */
return #
}
在調用func之後一段時間,嘗試從該指針中讀取num的值,可能仍然能夠返回正確的值(1234),但是任何接下來的函數調用會覆蓋原來的棧爲num分配的空間。這時,再從該指針讀取num的值就不正確了。如果要使一個指向num的指針都返回正確的num值,則需要將該變量聲明爲static。
三、野指針的產生
野指針指的是還沒有初始化的指針。嚴格地說,編程語言中每個指針在初始化前都是野指針。
一般於未初始化時便使用指針就會產生問題。大多數的編譯器都能檢測到這一問題並警告用戶。
int f(int i)
{
char* cp; //cp is a wild pointer
static char*scp; //scp is not a wild pointer: staticvariables are initialized to 0
//at start and retain their values from the last call afterwards.
//Using this feature may be considered bad style if not commented
}
cp是一個野指針,scp不是野指針。靜態變量一開始被初始化爲0,從最後一次調用後保持着它們的值。如果沒有註釋,使用這個特性也許被視爲不良風格。
四、避免懸垂指針的產生
在 C/C++ 中,一種最簡單的技術是實現一個 free()(或類似的)替代版本或者 delete 析構器來保證指針的重置。然後,這個技術不會清除其他指針變量,它們含有該指針的副本。
/* Alternative version for free*/
void safefree(void **pp)
{
if(pp!=NULL){ /* safe check*/
free(*pp); /*deallocate chunk,note that free(NULL) is valid*/
*pp=NULL; /* reset original pointer*/
}
int function(int i)
{
char *p=NULL,*p2;
p=(char*)malloc(1000); /*get a chunk*/
p2=p; /*copy the pointer*/
/*use the chunk here*/
safefree(&p); /*safety freeing;does not effect p2 variable*/
safefree(&p); /*this second call won't fail*/
char c=*p2;/*p2 is still a dangling pointer ,so this is undefined behavior*/