C語言知識彙總 | 56-C語言NULL空指標以及void指標
一、NULL空指標
一個指標變數可以指向計算機中的任何一塊記憶體,不管該記憶體有沒有被分配,也不管該記憶體有沒有使用許可權,只要把地址給它,它就可以指向,C語言沒有一種機制來保證指向的記憶體的正確性,程式設計師必須自己提高警惕。
很多初學者會在無意間對沒有初始化的指標進行操作,這是非常危險的,請看下面的例子:
#include <stdio.h>
int main()
{
char *str;
gets(str);
printf("%s\n", str);
return 0;
}
這段程式沒有語法錯誤,能夠通過編譯和連結,但當使用者輸入完字串並按下Enter鍵時就會發生錯誤,在 Linux 下表現為段錯誤(Segment Fault),在 Windows 下程式直接崩潰。如果你足夠幸運,或者輸入的字串少,也可能不報錯,這都是未知的。
未初始化的區域性變數的值是不確定的,C語言並沒有對此作出規定,不同的編譯器有不同的實現,因此不要直接使用未初始化的區域性變數。上面的程式碼中,str 就是一個未初始化的區域性變數,它的值是不確定的,究竟指向哪塊記憶體也是未知的,大多數情況下這塊記憶體沒有被分配或者沒有讀寫許可權,使用 gets() 函式向它裡面寫入資料顯然是錯誤的。
建議對沒有初始化的指標賦值為 NULL,例如:
char *str = NULL;
NULL 是“零值、等於零”的意思,在C語言中表示空指標。從表面上理解,空指標是不指向任何資料的指標,是無效指標,程式使用它不會產生效果。
注意區分大小寫,null 沒有任何特殊含義,只是一個普通的識別符號。
很多庫函式都對傳入的指標做了判斷,如果是空指標就不做任何操作,或者給出提示資訊。更改上面的程式碼,給 str 賦值 NULL,看看會有什麼效果:
#include <stdio.h>
int main()
{
char *str = NULL;
gets(str);
printf("%s\n", str);
return 0;
}
執行程式後發現,還未等使用者輸入任何字元,printf() 就直接輸出了(null)
。我們有理由據此推斷,gets() 和 printf() 都對空指標做了特殊處理:
- gets() 不會讓使用者輸入字串,也不會向指標指向的記憶體中寫入資料;
- printf() 不會讀取指標指向的內容,只是簡單地給出提示,讓程式設計師意識到使用了一個空指標。
我們在自己定義的函式中也可以進行類似的判斷,例如:
void func(char *p)
{
if(p == NULL){
printf("(null)\n");
}else{
printf("%s\n", p);
}
}
這樣能夠從很大程度上增加程式的健壯性,防止對空指標進行無意義的操作。
其實,NULL 是在stdio.h
中定義的一個巨集,它的具體內容為:
#define NULL ((void *)0)
(void *)0
表示把數值 0 強制轉換為void *
型別,最外層的( )
把巨集定義的內容括起來,防止發生歧義。從整體上來看,NULL 指向了地址為 0 的記憶體,而不是前面說的不指向任何資料。
在程式的虛擬地址空間中,最低地址處有一段記憶體區域被稱為保留區,這個區域不儲存有效資料,也不能被使用者程式訪問,將 NULL 指向這塊區域很容易檢測到違規指標。
在大多數作業系統中,極小的地址通常不儲存資料,也不允許程式訪問,NULL 可以指向這段地址區間中的任何一個地址。
注意,C語言沒有規定 NULL 的指向,只是大部分標準庫約定成俗地將 NULL 指向 0,所以不要將 NULL 和 0 等同起來,例如下面的寫法是不專業的:
int *p = 0;
而應該堅持寫為:
int *p = NULL;
注意 NULL 和 NUL 的區別:NULL 表示空指標,是一個巨集定義,可以在程式碼中直接使用。而 NUL 表示字串的結束標誌 '\0',它是ASCII碼錶中的第 0 個字元。NUL 沒有在C語言中定義,僅僅是對 '\0' 的稱呼,不能在程式碼中直接使用。
二、void*指標
對於空指標 NULL 的巨集定義內容,上面只是對((void *)0)
作了粗略的介紹,這裡重點說一下void *
的含義。void 用在函式定義中可以表示函式沒有返回值或者沒有形式引數,用在這裡表示指標指向的資料的型別是未知的。
也就是說,void *
表示一個有效指標,它確實指向實實在在的資料,只是資料的型別尚未確定,在後續使用過程中一般要進行強制型別轉換。
C語言動態記憶體分配函式 malloc() 的返回值就是void *
型別,在使用時要進行強制型別轉換,請看下面的例子:
#include <stdio.h>
int main()
{
//分配可以儲存30個字元的記憶體,並把返回的指標轉換為 char *
char *str = (char *)malloc(sizeof(char) * 30);
gets(str);
printf("%s\n", str);
return 0;
}
執行結果:
https://blog.csdn.net↙
https://blog.csdn.net
相關文章
- C語言知識彙總 | 51-C語言字串指標(指向字串的指標)C語言字串指標
- c語言指標彙總C語言指標
- C語言指標基本知識C語言指標
- C語言指標C語言指標
- C語言指標(三):陣列指標和字串指標C語言指標陣列字串
- C語言指標(二) 指標變數 ----by xhxhC語言指標變數
- C語言 函式指標C語言函式指標
- C語言指標筆記C語言指標筆記
- C語言基礎-指標C語言指標
- C語言指標學習C語言指標
- C語言指標用法大全C語言指標
- C語言知識彙總 | 00-C語言知識彙總目錄C語言
- C語言基礎-1、指標C語言指標
- c語言實現this指標效果C語言指標
- 搞清楚C語言指標C語言指標
- C語言指標詳解(一)C語言指標
- C語言指標詳解(二)C語言指標
- C語言 指標與陣列C語言指標陣列
- GO語言————4.9、指標Go指標
- C語言指標常見問題C語言指標
- c語言-運算子,陣列,指標C語言陣列指標
- C語言指標總結大學霸IT達人C語言指標
- go 語言指標學習Go指標
- C語言指標應用程式設計C語言指標程式設計
- c 語言指標操作經典問題指標
- C語言學習之:指標與字串C語言指標字串
- c語言函式指標的定義C語言函式指標
- 滴水逆向筆記系列-c語言總結4-15.switch語句反彙編-16.指標1-17.指標2筆記C語言指標
- C語言指標和陣列筆試題C語言指標陣列筆試
- C語言第九周作業(指標變數,記憶體訪問,取址,空指標)C語言指標變數記憶體
- Go 語言指標符號 *和&Go指標符號
- C\C++語言重點——指標篇 | 為什麼指標被譽為 C 語言靈魂?(一文讓你完全搞懂指標)C++指標
- C語言第7題:指標總結(兩張表格重點***)C語言指標
- 如何掌握 C 語言的一大利器——指標?指標
- (C語言)使用指標列印陣列的內容C語言指標陣列
- c語言野指標與結構體指標動態記憶體分配小解C語言指標結構體記憶體
- C語言語法基礎--S2函式和指標C語言函式指標
- C語言系列之 指標與陣列總複習視訊教程C語言指標陣列