1.空指標
一般來說,程式的起始位址是從「**區」的0位址開始存放的(注:如果插入乙個記憶體分布圖,則更能說明問題,此處省略),但實際上現代作業系統並非如此,卻保留了從0開始的一塊記憶體。至於這塊記憶體到底有有多大,與具體的作業系統有關。如果程式試圖訪問這塊記憶體,則系統提示異常。
為什麼作業系統不是保留乙個位元組呢?由於記憶體管理是按頁來進行的,因此無法做到單獨保留乙個位元組。儘管如此,但還是有極少數系統設定ram區從0位址開始,但指向有效變數的指標不會指向0位址。即使「**區」從0位址開始,但在任何情況下,0位址都不是c語言中任何函式的起始位址,因此指向有效函式位址的指標也不會指向0位址。
毫無疑問,任何一種指標型別都有乙個特殊的指標值,即空指標。它既不會指向任何物件或函式,也不是任何物件或函式的位址。而未初始化的指標,則完全可能指向任何地方。
由此可見,空指標與未初始化的指標是完全不同的兩個概念。那麼,將如何在程式中獲得乙個空指標呢?
2. 空指標常量與null
標準c規定,在初始化、賦值或比較時,如果一邊是變數或指標型別的表示式,則編譯器可以確定另一邊的常數0為空指標,並生成正確的空指標值。即在指標上下文中「值為0的整型常量表示式」在編譯時轉換為空指標。
為了讓程式中的空指標使用更加明確,標準c專門定義了乙個標準預處理巨集null,其值為「空指標常量」,通常為0或(void *)0,即在指標上下文中null與0是等價的,而未加修飾的0也是完全可以接受的。由於void *指標的特殊賦值屬性,比如:
#define null ((void *)0)
當null定義為((void *)0)時,即null是可以賦值給任何型別指標的值,它的型別為void*,而不是整數0,因此初始化「file *fp = null;」是完全合法的。
而為了區分整數0和空指標0,當需要其它型別的0的時候,即使可能工作,但也不能使用null,如果這樣處理其格式是錯誤的,這在非指標上下文中是不能工作的。特別地,不能在需要ascii空字元(nul)的地方使用null。如果確實需要,則可以自定義為:
#define nul '\0'
由此可見,常數0是乙個空指標常量,而null僅僅是它的乙個別名。
3. 空指標的用途
一般來說,未初始化是不能使用的非法指標,因為它完全有可能指向任何地方,從而導致程式無法判斷它為非法指標。因此,不管指標變數是全域性的還是區域性的、靜態的還是非靜態的,都應該在宣告它的同時進行初始化,要麼賦予乙個有效的位址,要麼賦予null。
標準c規定,全域性指標變數的預設值為null,而對於區域性指標變數則必須明確地指定其初值。因此,void通常用於指標變數的初始化,用來判斷乙個指標的有效性。比如:
unsigned char *pucbuf=(void *)0;
// 定義pucbuf為unsigned char型別指標並初始化為空指標
如果後續的**忘記初始化指標而直接使用的話,則可能造成程式失敗。雖然空指標也是非法指標,但可以通過程式判斷並告訴程式設計師**可能有問題。也就是說,如果一開始就將指標初始化為空指標,則可避免程式異常。比如:
if(pucbuf==0)
由於void型別指標的不確定性,因此它可以指向任意型別的資料,那麼只要在使用時做乙個簡單的強制型別轉換就可以了。比如:
unsignned char *pcdata = null;
// 定義pcdata為unsigned char型別指標
void
*pvdata;
// 定義pvdata為void型別指標
pvdata = pcdata;
// 無需進行強制型別轉換
pcdata = (unsigned char*) pvdata;
// 將pvdata強制轉換為unsigned char型別指標
顯然不存在void型別的物件,也就是說,當物件為空型別時,其大小為0位元組;當物件未確定型別時,那麼它的大小也是未確定的,因此不能宣告void型別變數。比如:
void a;
// 非法宣告
既然上述宣告是非法的,那麼,也就不能將sizeof運算子用於void型別。也就意味著,編譯器不知道所指物件的大小,由於指標的算術運算總是基於所指物件的大小的,因此不允許對void指標進行算術運算。
總之,在指標宣告中,void *表示通用指標的型別。如果void作為函式的返回型別,則表示不返回任何值。如果void位於引數列表中,則表示沒有引數。
4. 用無型別指標作為函式引數
由於c語言中最小長度的變數為char型別(包括unsigned char、signed char等),其sizeof(char)的結果為1,而其它任何變數的長度都是它的整數倍。比如,如果使用sdcc51編譯器,其sizeof(int)為2。因為通用swap函式函式不知道需要交換的變數的型別,所以需要乙個引數給出相應的指示。由於c語言的變數型別多種多樣,因此不可能為每一種變數型別編號,而且swap並不關心變數的真正型別,所以可以用變數的長度代替變數型別。通用swap函式的原型為:
void swap(void *pvdata1, void *pvdata2, int idatasize)
將a,b兩個變數(變數型別必須一樣)的值交換的**如下:
swap(&a, &b, sizeof(a));
通用swap排序函式的參考**見程式清單1.1。
//程式清單1.1 通用swap排序函式
void swap (void *pvdata1, void *pvdata2, int idatasize)
while (--idatasize > 0);
}
void及void指標詳解
1.概述 許多初學者對c c 語言中的void及void指標型別不甚理解,因此在使用上出現了一些錯誤。本文將對void關鍵字的深刻含義進行解說,並詳述void及void指標型別的使用方法與技巧。2.void的含義 void的字面意思是 無型別 void 則為 無型別指標 void 可以指向任何型別的...
void用法詳解
void的字面意思是 無型別 void 則為 無型別 指標 void 可以指向任何型別的資料。void幾乎只有 注釋 和限制程式的作用,定義乙個void變數沒有意義,不妨試著定義 void a 這行語句編譯時會出錯,提示 illegal use of type void 不過,即使void a的編譯...
void指標詳解
void指標的理解和使用都是比較複雜的,尤其與其他形式定義結合時,就顯得更為複雜了。下面就綜合網上一些資料,介紹一下void的用法。1.void指標是一種特別的指標 void vp 說它特別是因為它沒有型別 或者說這個型別不能判斷出指向物件的長度 2.任何指標都可以賦值給void指標 type p ...