关于空指针(指针指向为NULL)和void类型的指针的理解
正在學C,書上老說空指針,或者說void指針,對于我這樣的生手來說,理解非常容易造成混淆,因為void這個單詞的意思也是空,到底空指針的意思是指指向地址為空的類型呢,還是指void類型的指針呢
(1)空指針所對應的是指指向的對象為空的指針。
? ? ? ? ? ?不經(jīng)發(fā)問,什么叫指向為空呢?要理解這點,必須理解如下幾點(有點啰嗦,但很細,別嫌我煩):(a)任何指針都有類型(說穿了指針都是變量,只不過變量中的儲存的是地址而已),這里也包括void ?類型,其實它和常見的int,char一樣只不過是一種儲存類型。那試想一下,指針如果只是為了指向 一個地址的話,為毛還需要包含類型呢?我的理解是,指針之所以要加上類型,這樣能夠方便他和各種類的指向切換,怎么理解前面這句話呢?假設計算機是以字節(jié)編址的,也就是說,每個地址所 存儲的為8個位,假設現(xiàn)在機器中int為32個位(也就是4個字節(jié)),這樣的話,如果沒有類型,單純指針的進行p++(p為指針,沒有類型,實際上就是void類型的指針),我們知道p所存儲的是一個 地址,而地址實質上就是一個值,在計算機中,一個地址的值一般是以0x開頭的16進制的數(shù)字保存。例如:0x cccccccc,如果p++,則p變成0x cccccccd,僅僅在數(shù)值上加了1,這樣就無法實現(xiàn)各類型指針的自加自減運算。為了給指針運算的方便,所以給指針添加了類型,例如給指針限定為int型,由于int類型是4個字節(jié),如果當前指針p的地址為0x 00000001,由于我們知道一個整型需要4個字節(jié),每個字節(jié)占一個地址,對p進行類型限定后,會從p當前地址開始,連續(xù)找4個地址(按字節(jié)編址),對應4個儲存體來存儲一個整數(shù)類型,而p++所指向的將會是儲存完當前一個int型的下個整型地址的起始地址。其實際值應該為0x 00000005。以上是我對指針為毛要有類型的理解? ? ? ? ? ? ? ? ? ?
(b)什么叫指向指針為空?指針指向的是內存中的一塊儲存體的地址,什么叫指針為空。當你定義完 ? ?一個指針的時候,指針指向哪里嘞。我在VS2010中做的測試是指針所存儲的地址為0x cccccccc, 按照我的理解,這時候只是定義了一個指針啊,它什么也沒指向啊,這個時候所指向的時候應該說它是空指針呢,從常理的角度來想,可以說它是“空”指針,因為它指向的是一塊未知的內存區(qū)域。但實際上,這和公共定義上的空指針不同。c語言中定義,空指針,指針所指向內存中一塊特殊的區(qū)域,即我們一般在編譯中所使用的NULL中所存儲的地址,在VS2010中,這個地址為0x00000000,這塊不同的區(qū)域,根據(jù)編譯器的不同,可能會有差異
(c)那什么是void類型?什么是void類型的指針呢?對于這個問題,我的理解也不是很深刻。(1)void 類型,當它作為函數(shù)的類型定義時,它表示函數(shù)沒有返回值,或者說函數(shù)的返回值為空。(2)當 ?它用于指針聲明時,表示的是指針的類型為空,其本質為一個儲存單元的地址(具體編址規(guī)則不同計算機不同,所以只好說是儲存單元)。從理解上來說,你可以理解為一個沒有類型的指針(即一 個存儲單元的地址)
*********************************************************************************************************
void真正發(fā)揮的作用在于:?
(1) 對函數(shù)返回的限定;?
(2) 對函數(shù)參數(shù)的限定。
眾所周知,如果指針p1和p2的類型相同,那么我們可以直接在p1和p2間互相賦值;如果p1和p2指向不同的數(shù)據(jù)類型,則必須使用強制類型轉換運算符把賦值運算符右邊的指針類型轉換為左邊指針的類型。?
例如:
float *p1;
int *p2;
p1 = p2;
p1 = (float *)p2;
而void *則不同,任何類型的指針都可以直接賦值給它,無需進行強制類型轉換:
void *p1;
int *p2;
p1 = p2;
void *p1;
int *p2;
p2 = p1;
下面給出void關鍵字的使用規(guī)則:
規(guī)則一 如果函數(shù)沒有返回值,那么應聲明為void類型
在C語言中,凡不加返回值類型限定的函數(shù),就會被編譯器作為返回整型值處理。但是許多程序員卻誤以為其為void類型。例如:
add ( int a, int b )
{
return a + b;
}
int main(int argc, char* argv[])
{
printf ( "2 + 3 = %d", add ( 2, 3) );
}
2 + 3 = 5?
這說明不加返回值說明的函數(shù)的確為int函數(shù)。
???《高質量C/C++編程》中提到:“C++語言有很嚴格的類型安全檢查,不允許上述情況(指函數(shù)不加類型聲明)發(fā)生”??墒蔷幾g器并不一定這么認定,譬如在Visual C++6.0中上述add函數(shù)的編譯無錯也無警告且運行正確,所以不能寄希望于編譯器會做嚴格的類型檢查。
因此,為了避免混亂,我們在編寫C/C++程序時,對于任何函數(shù)都必須一個不漏地指定其類型。如果函數(shù)沒有返回值,一定要聲明為void類型。這既是程序良好可讀性的需要,也是編程規(guī)范性的要求。另外,加上void類型聲明后,也可以發(fā)揮代碼的“自注釋”作用。代碼的“自注釋”即代碼能自己注釋自己。
規(guī)則二 如果函數(shù)無參數(shù),那么應聲明其參數(shù)為void
在C++語言中聲明一個這樣的函數(shù):
int function(void)
{
return 1;
}
function(2);
因為在C++中,函數(shù)參數(shù)為void的意思是這個函數(shù)不接受任何參數(shù)。我們在Turbo C 2.0中編譯:
#include "stdio.h"
fun()
{
return 1;
}
main()
{
printf("%d",fun(2));
getchar();
}
所以,無論在C還是C++中,若函數(shù)不接受任何參數(shù),一定要指明參數(shù)為void。
規(guī)則三 小心使用void指針類型
按照ANSI(American National Standards Institute)標準,不能對void指針進行算法操作,即下列操作都是不合法的:
void * pvoid;
pvoid++; //ANSI:錯誤
pvoid += 1; //ANSI:錯誤
//ANSI標準之所以這樣認定,是因為它堅持:進行算法操作的指針必須是確定知道其指向數(shù)據(jù)類型大小的。
//例如:
int *pint;
pint++; //ANSI:正確
但是大名鼎鼎的GNU(GNU's Not Unix的縮寫)則不這么認定,它指定void *的算法操作與char *一致。
因此下列語句在GNU編譯器中皆正確:
pvoid++; //GNU:正確
pvoid += 1; //GNU:正確
在實際的程序設計中,為迎合ANSI標準,并提高程序的可移植性,我們可以這樣編寫實現(xiàn)同樣功能的代碼:?
void * pvoid;
(char *)pvoid++; //ANSI:正確;GNU:正確
(char *)pvoid += 1; //ANSI:錯誤;GNU:正確
規(guī)則四 如果函數(shù)的參數(shù)可以是任意類型指針,那么應聲明其參數(shù)為void *
典型的如內存操作函數(shù)memcpy和memset的函數(shù)原型分別為:
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
這樣,任何類型的指針都可以傳入memcpy和memset中,這也真實地體現(xiàn)了內存操作函數(shù)的意義,因為它操作的對象僅僅是一片內存,而不論這片內存是什么類型。如果memcpy和memset的參數(shù)類型不是void *,而是char *,那才叫真的奇怪了!這樣的memcpy和memset明顯不是一個“純粹的,脫離低級趣味的”函數(shù)!
下面的代碼執(zhí)行正確:
//示例:memset接受任意類型指針
int intarray[100];
memset ( intarray, 0, 100*sizeof(int) ); //將intarray清0
//示例:memcpy接受任意類型指針
int intarray1[100], intarray2[100];
memcpy ( intarray1, intarray2, 100*sizeof(int) ); //將intarray2拷貝給intarray1
規(guī)則五 void不能代表一個真實的變量
下面代碼都企圖讓void代表一個真實的變量,因此都是錯誤的代碼:
void a; //錯誤
function(void a); //錯誤
void的出現(xiàn)只是為了一種抽象的需要,如果你正確地理解了面向對象中“抽象基類”的概念,也很容易理解void數(shù)據(jù)類型。正如不能給抽象基類定義一個實例,我們也不能定義一個void(讓我們類比的稱void為“抽象數(shù)據(jù)類型”)變量。
總結
以上是生活随笔為你收集整理的关于空指针(指针指向为NULL)和void类型的指针的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++的:: . :-的区别
- 下一篇: C/C++指向指针的指针