前面兩文中內存錯誤釋放以及錯誤訪問指向棧的指針,從另外角度,其中一部分錯誤還可以歸結爲訪問了野指針。野指針又稱懸掛指針,代表那些指向不可用內存區域的指針。操作野指針,程序會發生難以預料的錯誤。形成野指針主要有以下原因:
1)指針沒有初始化。指針變量創建時不會自動指向null,其缺省值是隨機的,比如:
int *p;
*p = 0;
這種代碼可能導致死機或者非法操作,所以使用指針前一定要初始化,使它指向分配好的可用空間,否則就成了野指針。
2)內存free後,指向內存的指針被誤當作合法指針而繼續使用。例如下例:
char *p = (char *) malloc(100);
strcpy(p, “hello”);
free(p); // p 所指的內存被釋放,但是p所指的地址仍然不變
……
if(p != NULL) // 沒有起到預防作用,因爲p值未變
strcpy(p, “world”); // 出錯,訪問野指針
初學者在釋放鏈表時也很容易犯類似錯誤:
while (p)
{
free(p);
q = p->next; //p已釋放,p->next是訪問野指針
p = q;
}
這裏代碼順序很敏感,上面的順序會導致野指針訪問,正確方法是:
while (p)
{
q= p->next;
delete p;
p= q;
}
如果多個指針指向同一內存,這一問題也經常發生。free某個指針釋放了內存,其他指針即刻被懸掛成爲野指針,如果不注意而繼續訪問就會出錯。
3)指針指向失效的棧內存,比如:某子函數返回一指針,此指針指向子函數內部某局部變量,子函數退出後,該局部變量所在的棧內存就因自動出棧而釋放,而這個返回的指針也就成了野指針,不能再使用了。具體見下節例子。
總之,野指針和正常指針都指向某塊內存,只是野指針所指的內存已不可用。就象一張失效的藏寶圖,寶藏如果不在,藏寶圖自然就成了廢紙一張。所謂的懸掛也是表達類似含義。另外要注意區分野指針和空指針概念:野指針不特指空指針,而是指向垃圾(不可用)內存的指針。可以用if(ptr==null)預防空指針,但對野指針不起作用。所以野指針比空指針更隱蔽,危害更大。
思考下,內存重複free的錯誤是不是第二次free訪問了野指針?大家可以發表意見。