指針是一個變量,其存儲的是值的地址,而不是值本身。
對變量應用地址運算符(&),就可以獲得它的位置。
使用常規變量時,值是指定的量,而地址為派生量。下面來看看指針策略,它是C++內存管理編程理念的核心。
指針與C++基本原理
面向對象編程與傳統的過程性編程的區別在於,OPP強調的是在運行階段(而不是編譯階段)進行決策。運行階段指的是程序正在運行時,編譯階段指的是編譯器將程序組合起來時。
運行階段決策提供了靈活性,可以根據當時的情況進行調整。在運行階段做決策並非OPP獨有的,但使用C++編寫這樣的代碼比使用C語言簡單。
處理存儲數據的新策略剛好相反,將地址視為指定的量,而將值視為派生量。一種特殊類型的變量——指針用於存儲值得地址。因此,指針名表示的是地址。*運算符被稱為間接值或解除引用運算符,將其應用於指針,可以得到該地址處存儲的值(這和乘法使用的符號相同;C++根據上下文來確定所指的是乘法還是解除引用)。例如,假設manly是一個指針,則manly表示的是一個地址,而*manly表示存儲在該地址處的值。*manly與常規int變量等效。
聲明和初始化指針
指針聲明必須指定指針指向的數據的類型。
int*P_updates
這表示,*p_updates的類型為int。由於*運算符被用於指針,因此p_updates變量本身必須是指針。我們說p_updates指向int類型,我們還說p_updates的類型是指向int的指針,或int*。可以這樣說,p_updates是指針(地址),而*p_updates是int,而不是指針。
int *ptr;//傳統上,C程序員使用這種格式。這強調*ptr是一個int類型的值。 int* ptr;//很多C++程序員使用這種格式。這強調的是:int*是一種類型——指向int的指針。 /*下面的聲明創建一個指針(p1)和一個int變量(p2)*/ int* p1,p2; /*對每個指針變量名,都需要使用一個*
在C++中,int*是一種復合類型,是指向int的指針。
*/
可以在聲明語句中初始化指針。在這種情況下,被初始化的是指針,而不是它指向的值。也就是說,下面的語句將pt(而不是*pt)的值設置為&higgens:
int higgens=5; int* pt=&higgens;
指針的危險
極其重要的一點是:在C++創建指針時,計算機將反派用來存儲地址的內存,但不會分配用來存儲指針所指向的數據的內存。為數據提供空間是一個獨立的步驟,忽略這一步無疑是自找麻煩,如下所示:
long* fellow; *fellow=223323;
fellow確實是一個指針,但它指向哪裡呢?上述代碼沒有將地址賦給fellow。由於fellow沒有被初始化,它可能有任何值。不管值是什麼,程序都將它解釋為存儲223323的地址。如果fellow的值碰巧是1200,計算機將把數據放在地址,計算機將把數據放在地址1200上,即使這恰巧是程序代碼的地址。fellow指向的地方很可能並不是所要存儲223323的地方。這種錯誤可能會導致一些最隱匿、最難以跟蹤的bug。
一定要在對指針應用解除引用運算符(*)之前,將指針初始化為一個確定的、適當的地址。這是關於使用指針的金科玉律。
指針和數字
不能簡單地將整數賦給指針:
int* pt; pt=0xB8000000;
在這裡,左邊是指向int的指針,因此可以把它賦給地址,但右邊是一個整數。您可能知道,0xB8000000是老式計算機系統中視頻內存的組合段偏移地址,但這條語句並沒有告訴程序,這個數字就是一個地址。在C99標准發布之前,C語言允許這樣賦值。但C++在類型一致方面的要求更嚴格,編譯器將顯示一條錯誤信息,通告類型不匹配。要將數字值作為地址來使用,應通過強制類型轉換將數字轉換為適當的地址類型:
int* pt; pt=(int*)0xB8000000;
使用new來分配內存
/*use_new.cpp*/ #include<iostream> int main() { using namespace std; int nights = 1001; /*使用new為int類型的數據對象分配內存。這是在程序運行時進行的。 有了指針,就可以像使用變量那樣使用*pt。將值賦給*pt,從而將這些值賦給新的數據對象。 new分配的內存塊通常與常規變量聲明分配的內存塊不同。變量nights和pd的值都儲存在被稱為棧(stack)的內存區域中,而new從被稱為堆(heap)或自由存儲區(free store)的內存區域分配內存*/ int* pt = new int; *pt = 1001; cout << "nights 的值="; cout << nights << ":地址" << &nights << endl; cout << "整型"; cout << "值=" << *pt << ":地址=" << pt << endl; double*pd = new double; *pd = 10000001.1; cout << "浮點型"; cout << "值=" << *pd << ":地址=" << pd << endl; cout << "指針pd的地址:" << &pd << endl; cout << "pt的大小=" << sizeof(pt); cout << "*pt的大小=" << sizeof(*pt) << endl; cout << "pd的大小=" << sizeof pd; cout << ":*pd的大小=" << sizeof(*pd) << endl; cin.get(); cin.get(); return 0; }
使用new來創建動態數組
/*arranew.cpp*/ #include<iostream> int main() { using namespace std; /*為數組分配內存的通用格式:type_name* pointer_name=new name[num_elements];*/ double* p3 = new double[3]; p3[0] = 0.2; p3[1] = 0.5; p3[2] = 0.8; cout << "p3[1] is" << p3[1] << ".\n"; /*不能修改數組名的值。但指針是變量,因此可以修改它的值。 p3加1導致它指向第2個元素而不是第1個*/ p3 = p3 + 1; cout << "Now p3[0] is" << p3[0] << "and"; cout << "p3[1] is" << p3[1] << ".\n"; /*p3減1後,指針將指向原來的值,這樣程序便可以給delete[]提供正確的地址。*/ p3 = p3 - 1; /*方括號告訴程序,應釋放整個數組,而不僅僅是指針指向的元素*/ delete[]p3; cin.get(); cin.get(); return 0; }
輸出
p3[1] is 0.5. Now p3[0] is 0.5 and p3[1] is 0.8.