本文和大家分享的主要是c
語言
空指針NULL
以及
void
指針相關(guān)內(nèi)容,一起來看看吧,希望對大家
學習c語言有所幫助。
空指針 NULL
一個指針變量可以指向計算機中的任何一塊內(nèi)存,不管該內(nèi)存有沒有被分配,也不管該內(nèi)存有沒有使用權(quán)限,只要把地址給它,它就可以指向,C
語言沒有一種機制來保證指向的內(nèi)存的正確性,程序員必須自己提高警惕。
很多初學者會在無意間對沒有初始化的指針進行操作,這是非常危險的,請看下面的例子:
1. #include
2. int main () {
3. char * str ;
4. gets ( str );
5. printf ( "%s \n " , str );
6. return 0 ;
7. }
這段程序沒有語法錯誤,能夠通過編譯和鏈接,但當用戶輸入完字符串并按下回車鍵時就會發(fā)生錯誤,在 Linux
下表現(xiàn)為段錯誤(
Segment Fault
),在
Windows
下程序直接崩潰。如果你足夠幸運,或者輸入的字符串少,也可能不報錯,這都是未知的。
前面我們講過,未初始化的局部變量的值是不確定的,C
語言并沒有對此作出規(guī)定,不同的編譯器有不同的實現(xiàn),我曾警告大家不要直接使用未初始化的局部變量。上面的代碼中,
str
就是一個未初始化的局部變量,它的值是不確定的,究竟指向哪塊內(nèi)存也是未知的,大多數(shù)情況下這塊內(nèi)存沒有被分配或者沒有讀寫權(quán)限,使用
gets()
函數(shù)向它里面寫入數(shù)據(jù)顯然是錯誤的。
我強烈建議對沒有初始化的指針賦值為 NULL
,例如:
char *str = NULL;
NULL
是
“
零值、等于零
”
的意思,在
C
語言中表示空指針。從表面上理解,空指針是不指向任何數(shù)據(jù)的指針,是無效指針,程序使用它不會產(chǎn)生效果。
注意區(qū)分大小寫,null
沒有任何特殊含義,只是一個普通的標識符。
很多庫函數(shù)都對傳入的指針做了判斷,如果是空指針就不做任何操作,或者給出提示信息。更改上面的代碼,給 str
賦值
NULL
,看看會有什么效果:
1. #include
2. int main () {
3. char * str = NULL ;
4. gets ( str );
5. printf ( "%s \n " , str );
6. return 0 ;
7. }
運行程序后發(fā)現(xiàn),還未等用戶輸入任何字符,printf()
就直接輸出了
(null)
。我們有理由據(jù)此推斷,gets()
和
printf()
都對空指針做了特殊處理:
· gets()
不會讓用戶輸入字符串,也不會向指針指向的內(nèi)存中寫入數(shù)據(jù);
· printf()
不會讀取指針指向的內(nèi)容,只是簡單地給出提示,讓程序員意識到使用了一個空指針。
我們在自己定義的函數(shù)中也可以進行類似的判斷,例如:
1. void func ( char * p ) {
2. if ( p == NULL ) {
3. printf ( "(null) \n " );
4. } else {
5. printf ( "%s \n " , p );
6. }
7. }
這樣能夠從很大程度上增加程序的健壯性,防止對空指針進行無意義的操作。
其實,NULL
是在
stdio.h
中定義的一個宏,它的具體內(nèi)容為:
#define NULL ((void *)0)
(void *)0
表示把數(shù)值 0
強制轉(zhuǎn)換為
void *
類型,最外層的
( )
把宏定義的內(nèi)容括起來,防止發(fā)生歧義。從整體上來看,NULL
指向了地址為
0
的內(nèi)存,而不是前面說的不指向任何數(shù)據(jù)。
在進程的虛擬地址空間中,最低地址處有一段內(nèi)存區(qū)域被稱為保留區(qū),這個區(qū)域不存儲有效數(shù)據(jù),也不能被用戶程序訪問,將NULL
指向這塊區(qū)域很容易檢測到違規(guī)指針。
關(guān)于虛擬地址空間的概念以及程序的內(nèi)存分布,我們將在《
C語言和內(nèi)存
》專題中深入講解,現(xiàn)在讀者只需要記住,在大多數(shù)操作系統(tǒng)中,極小的地址通常不保存數(shù)據(jù),也不允許程序訪問,NULL
可以指向這段地址區(qū)間中的任何一個地址。
注意,C
語言沒有規(guī)定
NULL
的指向,只是大部分標準庫約定成俗地將
NULL
指向
0
,所以不要將
NULL
和
0
等同起來,例如下面的寫法是不專業(yè)的:
int *p = 0;
而應該堅持寫為:
int *p = NULL;
注意 NULL
和
NUL
的區(qū)別:
NULL
表示空指針,是一個宏定義,可以在代碼中直接使用。而
NUL
表示字符串的結(jié)束標志
'\0'
,它是
ASCII
碼表中的第
0
個字符。
NUL
沒有在
C
語言中定義,僅僅是對
'\0'
的稱呼,不能在代碼中直接使用。
void 指針
對于空指針 NULL
的宏定義內(nèi)容,上面只是對
((void *)0)
作了粗略的介紹,這里重點說一下
void *
的含義。void
用在函數(shù)定義中可以表示函數(shù)沒有返回值或者沒有形式參數(shù),用在這里表示指針指向的數(shù)據(jù)的類型是未知的。
也就是說,
void *
表示一個有效指針,它確實指向?qū)崒嵲谠诘臄?shù)據(jù),只是數(shù)據(jù)的類型尚未確定,在后續(xù)使用過程中一般要進行強制類型轉(zhuǎn)換。
C
語言動態(tài)內(nèi)存分配函數(shù)
malloc()
的返回值就是
void *
類型,在使用時要進行強制類型轉(zhuǎn)換,請看下面的例子:
純文本復制
1. #include
2. int main () {
3. //
分配可以保存
30
個字符的內(nèi)存,并把返回的指針轉(zhuǎn)換為
char *
4. char * str = ( char *) malloc ( sizeof ( char ) * 30 );
5. gets ( str );
6. printf ( "%s \n " , str );
7. return 0 ;
8. }
運行結(jié)果:
c.biancheng.net↙
c.biancheng.net
這里重點是讓大家理解
void *
,它不是空指針的意思,而是實實在在的指針,只是指針指向的內(nèi)存中不知道保存的是什么類型的數(shù)據(jù)。
來源:csdn