對於空(null)指針與 NULL 指針,相信許多讀者對它們之間的關系都很迷惑,甚至有很大一部分讀者會認為它們根本就是一回事。其實不然,它們之間存在着一定的本質區別,下面就來詳細闡述它們之間的不同。
對於空(null)指針的概念,在 C 標准中明確地定義:值為 0 的整型常量表達式,或強制(轉換)為“void*”類型的此類表達式,稱為空指針常量。
當將一個空指針常量賦予一個指針或與指針作比較時,將把該常量轉換為指向該類型的指針,這樣的指針稱為空指針。空指針在與指向任何對象或函數的指針作比較時保證不會相等。
根據上面的定義,我們可以對空指針做如下幾點剖析:
1) 每一種指針類型都有一個空指針,它與同類型的其他所有指針值都不相同。
2) 由系統保證空指針不指向任何實際的對象或函數,也就是說,任何對象或者函數的地址都不可能是空指針,空指針與任何對象或函數的指針值都不相等。因此,取地址操作符 & 永遠也不能得到空指針,同樣對 malloc() 函數的成功調用也不會返回空指針,但如果調用失敗,則 malloc() 函數返回空指針。
3) 空指針表示“未分配”或者“尚未指向任何地方”。它與未初始化的指針有所不同,空指針可以確保不指向任何對象或函數,而未初始化指針可能指向任何地方。
4) 0、0L、'\0'、3-3、0*17以及(void*)0等都是空指針常量,則:
int *p;
p=0;
/*或者*/
p=0l;
/*或者*/
p='\0';
/*或者*/
p=3-3;
/*或者*/
p=0*17;
/*或者*/
p=(void*)0;
指針變量 p 經過上面任何一種賦值操作之后都將成為一個空指針。至於編譯時系統究竟選取哪種形式作為空指針常量使用,則與具體實現相關。在一般情況下,對於 C 語言系統,選擇“(void*)0”或 0 的居多(也有個別的選擇 0L);而對於 C++ 語言系統,由於存在嚴格的類型轉化的要求,“void*”不能像在 C 語言中那樣自由轉換為其他指針類型,所以通常只選 0 作為空指針常量,而不選擇“(void*)0”。
5) 對於空指針究竟指向內存的什么地方,在標准中並沒有明確規定。也就是說,用哪個具體的地址值(0 地址還是某一特定地址)來表示空指針完全取決於系統的實現。在一般情況下,空指針指向 0 地址,即空指針的內部用全 0 來表示,也可以稱它為零空指針。當然,也有一些系統用一些特殊的地址值或特殊的方式來表示空指針,也可以稱它為非零空指針。
但在實際編程中,我們並不需要了解在系統上的空指針到底是一個零空指針還是一個非零空指針。而我們僅僅只需要知道一個指針是否是空指針就可以了,編譯器會自動實現其中的轉換,為我們屏蔽其中的實現細節。因此,千萬不要把空指針的內部表示等同於整數0的對象表示,有時它們是不同的。
在了解空指針的概念之后,下面來看 NULL 指針。
作為一種良好的編程習慣,很多程序員都不願意在程序中到處出現未加修飾的 0 或者其他空指針常量。
為了讓程序中的空指針使用更加明確,從而保持統一的編程風格,標准 C 專門定義了一個標准預處理宏 NULL,其值為“空指針常量”,通常是 0 或者“((void*)0)”,即在指針上下文中的 NULL 與 0 是等價的,而未加修飾的 0 也是完全可以接受的。
如在 VC++ 中定義預處理宏 NULL 的代碼如下:
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
這里需要說明的是,當 NULL 定義為“((void *)0)”時,即 NULL 是可以賦值給任何類型指針的值,它的類型為 void*,而不是整數 0,因此初始化“FILE*fp=NULL;”是完全合法的。
而為了區分整數 0 和空指針 0,當需要其他類型的 0 時,即使可能工作,也不能使用 NULL,因為這樣處理其格式是錯誤的,這種類型在非指針上下文中是不能工作的。特別需要注意的是,不能在需要 ASCII 空字符(NUL)的地方使用 NULL。如果確實需要,則可以自定義為:
#define NUL '\0'
由此可見,常數 0 是一個空指針常量,而 NULL 僅僅是它的一個別名。NULL 可以確保是 0,但空(null)指針卻不一定。不管你是轉行也好,初學也罷,進階也可,如果你想學編程,進階程序員~
【值得關注】我的 編程學習交流俱樂部 !【點擊進入】
C語言入門資料:
C語言必讀書籍:
