“野指針”的成因主要有三種:
1)指針變量沒有被初始化。任何指針變量剛被創建時不會自動成為NULL指針,它的缺省值是隨機的,它會亂指一氣。所以,指針變量在創建的同時應當被初始化,要麼將指針設置為NULL,要麼讓它指向合法的內存。例如:
char *p = NULL;
char *str = (char *) malloc(100);
2)指針p被free或者delete之後,沒有置為NULL,讓人誤以為p是個合法的指針。
free和delete只是把指針所指的內存給釋放掉,但並沒有把指針本身干掉。 free以後其地址仍然不變(非NULL),只是該地址對應的內存是垃圾,p成了“野指針”。如果此時不把p設置為NULL,會讓人誤以為p是個合法的指 針。如果程序比較長,我們有時記不住p所指的內存是否已經被釋放,在繼續使用p之前,通常會用語句if (p != NULL)進行防錯處理。很遺憾,此時if語句起不到防錯作用,因為即便p不是NULL指針,它也不指向合法的內存塊。
?char
*p = (
char
*)
malloc
(100);
strcpy
(p, “hello”);
free
(p);
// p 所指的內存被釋放,但是p所指的地址仍然不變
…
if
(p != NULL)
// 沒有起到防錯作用
{
strcpy
(p, “world”);
// 出錯
}
3)指針操作超越了變量的作用范圍。這種情況讓人防不勝防,示例程序如下:
?class
A
{
public
:
void
Func(
void
){ cout << “Func of
class
A” << endl; }
};
void
Test(
void
)
{
A *p;
{
A a;
p = &a;
// 注意 a 的生命期 ,只在這個程序塊中(花括號裡面的兩行),而不是整個test函數
}
p->Func();
// p是“野指針”
}
函數Test在執行語句p->Func()時,對象a已經消失,而p是指向a的,所以p就成了“野指針”。
1. 空指針、NULL指針、零指針
1.1什麼是空指針常量
0、0L、' '、3 - 3、0 * 17 (它們都是“integer constant expression”)以及 (void*)0 (我覺得(void*)0應該算是一個空指針吧,更恰當一點)等都是空指針常量(注意 (char*) 0 不叫空指針常量,只是一個空指針值)。至於系統選取哪種形式作為空指針常量使用,則是實現相關的。一般的 C 系統選擇 (void*)0 或者 0 的居多(也有個別的選擇 0L);至於 C++ 系統,由於存在嚴格的類型轉化的要求,void* 不能象 C 中那樣自由轉換為其它指針類型,所以通常選 0 作為空指針常量(C++標准推薦),而不選擇 (void*)0。
1.2 什麼是空指針
如果 p 是一個指針變量,則 p = 0; p = 0L; p = ' '; p = 3 - 3; p = 0 * 17; 中的任何一種賦值操作之後(對於 C 來說還可以是 p = (void*)0;), p 都成為一個空指針,由系統保證空指針不指向任何實際的對象或者函數。反過來說,任何對象或者函數的地址都不可能是空指針。(比如這裡的(void*)0就是一個空指針。把它理解為null pointer還是null pointer constant會有微秒的不同,當然也不是緊要了)。其實空指針只是一種編程概念,就如一個容器可能有空和非空兩種基本狀態。
1.3 NULL指針
NULL指針是不指向任何一個地址的指針。這樣的指針一般是允許的。當一個指針為NULL的時候,不要對它進行存取。
NULL 是一個標准規定的宏定義,用來表示空指針常量。因此,除了上面的各種賦值方式之外,還可以用 p = NULL; 來使 p 成為一個空指針。
(很多系統中的實現:#define NULL (void*)0,與這裡的“a null pointer constant”並不是完全一致的)
C++標准庫定義的NULL指針
?// Define NULL pointer value
#ifndef NULL
# ifdef __cplusplus
# define NULL 0
# else
# define NULL ((void *)0)
# endif
#endif // NULL
NULL是一個宏,在C++裡面被直接被定義成了整數立即數類型的0,而在沒有__cplusplus定義的前提下,就被定義成一個值是0的void *類型指針常量。
1.4 零指針
零值指針,是值為0的指針,可以是任何一種指針類型,可以是通用變體類型void*,也可以是char*,int*等等。
在C++裡面,任何一個概念都要以一種語言內存公認的形式表現出來,例如std::vector會提供一個empty()子函數來返回容器是否為 空,然而對於一個基本數值類型(或者說只是一個類似整數類型的類型)我們不可能將其抽象成一個類(當然除了auto_ptr等只能指針)來提供其詳細的狀 態說明,所以我們需要一個特殊值來做為這種狀態的表現。
C++標准規定,當一個指針類型的數值是0時,認為這個指針是空的。(我們在其他的標准下或許可以使用其他的特殊值來定義我們需要的NULL實現,可以是1,可以是2,是隨實現要求而定的,但是在標准C++下面我們用0來實現NULL指針)
1.5 空指針向了內存的什麼地方(空指針的內部實現)?