基礎資料型別 (Elementary Data Type)之二:指標一、指標:指標都有一個資料類型,指標的類型可以指示編譯器怎麼解釋特定地址上記憶體的內容,以及該記憶體地區應該跨越過多少記憶體單元。ü 如果一個int 型的指標定址到1000 記憶體處那麼在32 位元電腦上跨越的地址空間是1000~1003ü 如果一個double 型的指標定址到1000 記憶體處那麼在32 位元電腦上跨越的地址空間是1000~10071、定義:通過在標誌符前加一個解引用操作符(*)來定義指標,在逗號分隔的標誌符列表中,每個將被用做指標的標誌符前,都必須加上解引用操作符。如:int *ip1, *ip2;//兩個指標ip1和ip2標誌符前都要有解引用操作符*complex<double> *cp;string *pstring;vector<int> *pvec;double *dp;long *lp, lp2;//lp2是long型整數,不是long型指標float fp, *fp2;//fp是float型整數,不是float型指標一般,為了書寫清楚起見,我們應該這樣定義:string *str;而不應該定義成:string* str;當然,上面定義也是沒有錯誤的,但是不容易理解。int *i=0;int *i=NULL;上面兩個定義作用是一樣的,均表示整型指標i不指向任意記憶體單元。2、舉例:int iVal=1024;int *pi=0;int *pi2=&iVal;//pi2初始化為變數iVal的地址pi=pi2;//pi也指向iVal的地址pi=iVal;//錯誤,指標被賦值為int值iVal 3、指標不能被初始化為其他類型對象的地址:double dval;double *pd = &dval;//正確// 下面兩個定義都是編譯時間刻錯誤// 無效的類型賦值: int* <== double*pi = pd;pi = &dval;4、C++提供了一種特殊的指標類型void*,可以持有任意類型的地址值// ok: void* 可以持有任何指標類型的地址值void *pv = pi;pv = pd;上面,void*表明相關的值是個地址,但該地址的物件類型並不知道。我們不能夠操作空類型指標所指向的對象,只能夠傳送該地址值或將它與其他地址值做比較。5、用法已知一個int型指標pi:int *pi;那麼在使用時,pi表示包含在pi內部的int型資料的地址值;&pi表示記憶體中儲存pi的地址值。如果想獲得pi所指向的int型資料值,應該使用:*pi,從而解除對指標的引用。C++提供瞭解引用操作符以便間接訪問指標所指向的具體資料,例如:int ival = 1024, ival2 = 2048;int *pi = &ival;// 解除pi 的引用, 為它所指向的對象ival// 賦以ival2 的值*pi = ival2;// 對於右邊的執行個體, 讀取pi 所指對象的值// 對於左邊的執行個體則把右邊的運算式賦給對象*pi = abs( *pi ); // ival = abs(ival);*pi = *pi + 1; // ival = ival + 1;6、特殊用法:指向指標的指標int *pi = &ival;
//
實際上
*
標誌符左邊的資訊表示標誌符指標儲存的具體地址所指資料的類型,如下:int **ppi = π//ppi指標儲存的地址是pi指標的地址int *pi2 = *ppi;//對ppi解引用,擷取ppi指向的內容即pi指標的內容,即iVal的地址,賦給指標pi2 7、指標的加法操作:char *ch;int *pi;double *pd;ch+2;//表示前進兩個位元組的地址pi+2;//表示前進8個位元組的地址pd+2;//表示前進16個位元組的地址指標類型不同,每加1所前進的位元組數也是不同的。實際上,指標的加法操作主要用在數組上,例如:int ia[ 10 ];int *iter = &ia[0];int *iter_end = &ia[10];while ( iter != iter_end ) {do_something_with_value( *iter );++iter; // 現在iter 指向下一個元素} 測試題:1、已知下列定義int ival = 1024, ival2 = 2048;int *pi1 = &ival, *pi2 = &ival2, **pi3 = 0;說明下列賦值將產生什麼後果哪些是錯誤的(a) ival = *pi3; (e) pi1 = *pi3;(b) *pi2 = *pi3; (f) ival = *pi1;(c) ival = pi2; (g) pi1 = ival;(d) pi2 = *pi1; (h) pi3 = &pi2;答:a錯,*pi3表示指標pi3指向的記憶體單元的值,是一個整型地址值,而不是int。另外pi3是指標的指標,其值為0,解引用null指標會造成執行階段錯誤。 b錯,同a c錯,不能將指標賦值給整型變數 d錯,不能將整型資料賦值給整型指標 e錯,pi3是指標的指標,其值為0,解引用null指標會造成執行階段錯誤。 f正確 g錯,不能將整型資料賦值給整型指標 h正確。2、指標是C 和C++程式設計一個很重要的方面也是程式錯誤的常見起源例如pi = &ival2;pi = pi + 1024;幾乎可以保證pi 會指向記憶體的一個隨機地區這個賦值在做什麼什麼時候它不是一個錯誤答:如果pi指向一個不會越界的數組的話,這種操作還是有一定使用價值的。3、類似地下面的小程式的行為是未定義的可能在運行時失敗int foobar( int *pi ) {*pi = 1024;return *pi;}int main() {int *pi2 = 0;//定義時,指標pi2沒有指向一塊具體的記憶體,相當於沒有初始化。int ival = foobar( pi2 );return 0;}答:問題在於我們指標pi2在定義時,並未指向一塊已經分配的記憶體,那麼在footbar函數中,執行*pi=1024操作時,試圖將1024寫入地址0的記憶體中,除非指標pi2定義時被賦予一個實際值,否則foobar函數中,對pi指向的記憶體寫入1024時,就是錯誤的。改錯方法,就是在foobar函數中加上一個if判斷。4、在前面兩個練習中出現錯誤是因為缺少在運行時刻對指標使用的檢查如果指標在C++程式設計中起重要作用你認為為什麼沒有為指標的使用增加更多的安全性你能想到哪些指導規則能使指標的使用更加安全答:使用指標良好的習慣:總是將指標初始化,不要無視編譯器發出的錯誤資訊如“強制轉換為指標變數”等。