1. 程式人生 > 程式設計 >c++野指標的原理以及避免方法

c++野指標的原理以及避免方法

1.定義

指向非法的記憶體地址指標叫作野指標(Wild Pointer),也叫懸掛指標(Dangling Pointer),意為無法正常使用的指標。

2.出現野指標的常見情形

2.1使用未初始化的指標

出現野指標最典型的情形就是在定義指標變數之後沒有對它進行初始化,如下面的程式。

#include <iostream>
using namespace std;

int main()
{
  int* p;
  cout<<*p<<endl; //編譯通過,執行時出錯
}

2.2指標所指的物件已經消亡

指標指向某個物件之後,當這個物件的生命週期已經結束,物件已經消亡後,仍使用指標訪問該物件,將出現執行時錯誤。考察如下程式。

#include <iostream>
using namespace std;

int* retAddr()
{
  int num=10;
  return &num;
}

int main()
{
  int* p=NULL;
  p=retAddr();
  cout<<&p<<endl;
  cout<<*p<<endl;
}

以上程式編譯和執行都沒有錯誤,輸出結果如下:

001AFD48
1701495776

最後一行,輸出的並非想象中的num的值10,因為變數num是儲存在棧空間的區域性變數,離開函式超出其作用域後就會被釋放掉,因此輸出的值就是不確定的值了。

注意:
(1)如果將cout<<&p<< endl;註釋掉,可以正常輸出num的值為10,或者將cout<<*p<<endl;放在前面,也能正常輸出,原因是區域性變數num的記憶體空間雖然在函式retAddr()呼叫結束後被回收,但是其值還沒有被修改,語句cout<<&p<<endl;實際上是呼叫cout物件的成員函式ostream& operator<<(),重新使用了retAddr()呼叫時使用的棧空間,此時num的記憶體空間被改寫,輸出了不確定值。

(2)修改p指向的記憶體空間的值,可以正常編譯執行。

int main()
{
  int* p = NULL;
  p = retAddr();
  *p = 11;
  cout << *p << endl;
}

上面的程式碼輸出11。這裡p指向的地址空間雖然不屬於main函式的棧空間,但是作業系統在程式執行時會預先開闢一段可用的棧空間,供使用者程式使用。一般情況下,Windows預設為1M,Linux預設為10M,預先開闢的棧空間並不是系統保護性地址,可以由程式任意改寫並訪問,所以可以更改p指向的記憶體空間的值並訪問輸出。

2.3指標釋放後之後未置空

指標p被free或者delete之後,沒有置為NULL,讓人誤以為p是個合法的指標。對指標進行free和delete,只是把指標所指的記憶體空間給釋放掉,但並沒有把指標本身置空,此時指標指向的就是“垃圾”記憶體。釋放後的指標應立即將指標置為NULL,防止產生野指標。考察如下程式。

#include <iostream>
using namespace std;

int main()
{
  int* p=NULL;
  p=new int[10];
  delete p;
  cout<<"p[0]:"<<p[0]<<endl;
}

程式輸出結果是一個隨機值,因為此時的指標所指向的空間是垃圾記憶體,存放著隨機值。

3.如何避免野指標的出現

野指標有時比較隱蔽,編譯器不能發現,為了防止野指標帶來的危害,開發人員應該注意以下幾點。
(1)C++引入了引用機制,如果使用引用可以達到程式設計目的,就可以不必使用指標。因為引用在定義的時候,必須初始化,所以可以避免野指標的出現。

(2)如果一定要使用指標,那麼需要在定義指標變數的同時對它進行初始化操作。定義時將其置位NULL或者指向一個有名變數。

(3)對指標進行free或者delete操作後,將其設定為NULL。對於使用 free 的情況,常常定義一個巨集或者函式 xfree 來代替 free 置空指標:

#define xfree(x) free(x); x = NULL;

以上就是c++野指標的原理以及避免方法的詳細內容,更多關於c++ 野指標的資料請關注我們其它相關文章!