野指針
如果一個指針指向的內存沒有訪問權限,或者指向一塊已經釋放掉的內存,那么就無法對該指針進行操作,這樣的指針稱為野指針(Wild Pointer)。
指向沒有訪問權限的內存
請看下面的代碼:
#include <stdio.h>
int main(){
char *str;
gets(str);
puts(str);
return 0;
}
在GCC下運行,輸入一個字符串后會提示段錯誤(Segment Fault)。在VS下運行,輸入一個字符串后會提示類似下面的錯誤:

這是因為,str 是局部變量,它的值是不確定的,是隨機的,不知道指向哪塊內存。一般情況下,這塊內存要么沒有訪問權限,要么還沒有分配,當 gets() 函數試圖將讀取到的字符串寫入這塊內存時,必然會發生錯誤。
當然,如果足夠幸運的話,str 也可能恰好指向一段分配好的、並且有讀寫權限的內存,程序就運行成功了,但這是小概率事件,一般不會發生。
指向釋放掉的內存
請繼續看下面的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *str = (char*)malloc(20*sizeof(char));
strcpy(str, "C語言123456");
puts(str);
free(str);
if(str){
puts(str);
}
return 0;
}
運行程序,第一次輸出C語言123456,第二次輸出的是亂碼或者什么也不輸出。這是因為,free() 只是釋放掉了動態分配的內存,但並未改變 str 的值,str 的值不是 NULL,它仍然指向被釋放掉的內存,所以會執行 if 語句里面的 puts() 函數。但由於此時的內存已經被釋放掉了,原來的字符串已經不在了,所以輸出的數據是未知的。
這就提醒我們,使用 free() 釋放內存的同時要將指針置為NULL,否則下次就無法判斷指向的內存是否有效。
還有一種情況是函數外部指針指向函數內部的變量、數組等,請看下面的代碼:
#include <stdio.h>
void func(char **pp);
int main(){
char *pstr;
func(&pstr);
puts(pstr);
return 0;
}
void func(char **pp){
char arr[] = "C語言";
*pp = arr;
}
arr 數組在棧上分配內存,字符串"C語言"就存儲在這里,func() 函數運行結束后,這塊內存被釋放掉,但是函數外部的 pstr 仍然指向這里,所以執行puts(pstr);時,輸出結果是未知的。
規避野指針
要想規避野指針,就要養成良好的編程習慣:
-
指針變量如果暫時不需要賦值,一定要初始化為NULL,因為任何指針變量剛被創建時不會自動成為NULL指針,它的缺省值是隨機的。
-
當指針指向的內存被釋放掉時,要將指針的值設置為 NULL,因為 free() 只是釋放掉了內存,並為改變指針的值。
