1. 程式人生 > >C語言指標(關於定義指標為NULL)深入瞭解

C語言指標(關於定義指標為NULL)深入瞭解

C語言指標中:
指標是C語言最重要的概念之一,用於儲存變數的地址。
&是取地址運算子,*是間接運算子。(C語言中:%p是輸出地址的轉換說明)。
“*號在定義變數時,表示型別是指標,如 int *p = NULL 表示這是一個叫p的指標; *號在運算時,表示取指標指向地址的內容。
首先要說的是:非堆分配的記憶體是不需要free的。
再說p=NULL;指標的變化是 p指向了一個地址為0的記憶體,這就提醒別人不要對這個指標進行解引用的操作。NULL其實就是0x0。p=NULL後,p指向0x0這個地址。此處的地址,你沒有訪問許可權。
空指標指沒有定位記憶體的指標,值為null(0),你使用new或者malloc申請了指標p,使用後delete或者free,你必須將指標值設定為null,否則,p將成為一個非法指標,後續程式碼如果使用到該指標有可能會造成系統崩潰(記憶體不可以讀不可寫),或者,破壞自身有效記憶體資料(釋放後,又在申請作為別的用途,恰巧系統分配了同一塊記憶體)
free(p)是隻是將malloc申請的記憶體空間釋放,在不改變free()函式的原型前提下是無法做到P=NULL的,P=NULL相當於空指標,不指向任何有效的物件。絕對不允許間接使用空指標,否則程式會得到毫無用處的結果或者全部是零的值,或者會突然停止。P=null,之後,p還是原來的型別的,不變的。比如說 我定義了一個整形變數 int a = 1; 同時定義了一個指標p指向這個變數a: int *p = &a;
但我用完這個變數和指標的時候我把指標所指向的記憶體空間釋放掉:free(p);這個時候p所指向的記憶體空間裡面的資料1被清空的,但是指標p裡面仍然存有一個地址(原來指向a變數記憶體空間的地址),此時通常再要把指標p設定成空指標:P = NULL。我的問題來了:從free(p);這條語句到p = NULL;這條語句,指標p的狀態發生了哪些變化,到底什麼樣的指標才叫空指標?是不是P = NULL;之後,p裡面所存放的地址就為空了?是這樣理解嗎?此時p還有指向的資料型別嗎?比如說p還是一個int *型的指標嗎?
還有通常用if (p != NULL)來預防錯誤,就是說如果當指標p為空指標的時候,這個指標就最好不要用,要不然可能會發生記憶體洩露、空指標一場等錯誤,為什麼呢?

  1. int *p = &a; 這樣的指標不可用 free , free 只是針對 malloc, realloc 的記憶體進行釋放。
  2. 空指標是指指標指向地址0,如果是你分配的記憶體,並且使用 free 釋放,然後把指標置成 0 ,只是為了不進行非法的引用。

    char* tmp = (char*)malloc(1024);
    free(tmp);
    tmp = 0;

在 free 後,如果後面再引用 tmp, 因為是個空指標,會導致進行崩潰。
如果不置為0,比如
char* tmp = (char*)malloc(1024);
free(tmp);
char* tmp2 = (char*)malloc(1024);
memset(tmp, 0, 1024);
這樣,由於堆管理特性,很可能 memset(tmp, 0, 1024)寫了 tmp2 指向的空間。
這樣,釋放完 tmp 後,再使用它,謂之野指標。
使用野指標會造成不可預期的後果,而使用空指標會造成比較確定的後果:崩潰。
所以 釋放完後給指標賦成空,很大程度是避免以後錯誤地使用指標。
free(p)//報告系統,我要釋放記憶體,系統就將該記憶體塊標記為未使用,但不影響p的值
p = NULL//free被執行後,你需要將該指標標記為空,因為p指向的記憶體以被系統收回,不屬於你的程式
這兩個語句一般是在一起使用的
總結:為了避免野指標,定義指標的時候必須給指標初始化(以防指標空間的資料沒有及時清空),用free§釋放掉指標所指的記憶體空間後,必須立即同時把p賦值為NULL,避免後面程式指標P而導致意想不到的錯誤,甚至系統崩潰!”

#include<iostream>
using namespace std;
bool a[20000005];
int main() {
//1:
	int i=9999,j;
	int *p,*pp;
	p=&i;
	pp=&j;
	cout<<p<<" "<<pp<<endl;
	cout<<*p<<" "<<*pp<<endl;
	*p=i;
	cout<<p<<endl;
	cout<<*p<<endl;
//2:
	int *a;
	if(a == NULL) {
		cout<<a<<endl;
//		cout<<*a<<endl; 
		cout<<"NULL"<<endl;
	} else {
		cout<<a<<endl;
		cout<<"!"<<endl;
	}
	
//3:
    int array[5]={0,1,2,3,4,};  
    int *ptr=array;  
    for(int i=0;i<5;i++)  
    {  
        cout<<(*ptr)++<<endl;  
        ptr++;  
    }

	return 0;
}

對於2中的程式碼:定義一個a就結束了,也沒有給a賦值。這種指標為野指標,野指標指向不明,對程式有不可知的後果。通過執行程式可知野指標不是空的,當定義好之後,記憶體會隨機分配個記憶體空間的值。所以,通常在定義指標的時候順便賦值為"0"或者"NULL"(以防指標空間的資料沒有及時清空),這樣就可以將該指標懸空(不指向任何位置)。

指標函式:


Int (*p)(int);
 //從P 處開始,先與指標結合,說明P 是一個指標,然後與()結合,說明指標指向的是一個函式,然後再與()裡的int 結合,說明函式有一個int 型的引數,再與最外層的int 結合,說明函式的返回型別是整型,所以P 是一個指向有一個整型引數且返回型別為整型的函式的指標