程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++_系列自學課程_第_8_課_指針和引用_《C++ Primer 第四版》

C++_系列自學課程_第_8_課_指針和引用_《C++ Primer 第四版》

編輯:C++入門知識

C++_系列自學課程_第_8_課_指針和引用_《C++ Primer 第四版》


 C語言最富有迷幻色彩的部分當屬指針部分,無論是指針的定義還是指針的意義都可算是C語言中最復雜的內容。指針不但提供給了程序員直接操作硬件部分的操作接口,還提供給了程序員更多靈活的用法。C++繼承這一高效的機制,同時引入了另一個與指針相似但不相同的機制: 引用。       一、引用     簡單的來說,引用就是變量的別名(alias), 通過別名我們可以操作引用代表的變量。 定義一個引用的語法如下所示:       變量類型   &引用標識符 = 變量名。   Exp:   復制代碼   int  iVar=10;     int  &iRef = iVar;     iRef = 20 ;     cout<<iVar<<endl; 復制代碼   這段程序執行的結果就是輸出: 20 ;     程序通過引用 iRef 改變了變量iVar的值。   要點:     1、在定義引用的同事必須初始化,指出引用代表的是哪一個變量,而且這種“指向關系”不能改變。     2、引用只是對象的另一個名字,可以通過對象的原標識符訪問對象,也可以通過對象的引用訪問對象。     3、在一個語句定義多個引用的時候,每個引用標識符(引用名)的前面必須都加上&符號,否則就是錯誤。       1、const引用     const引用是指向const對象的引用, 不能通過const引用改變原對象的值。如下所示:       復制代碼  1 #include <iostream>  2 #include <string>  3 #include <vector>  4 #include <bitset>  5   6 using std::cin;  7 using std::cout;  8 using std::endl;  9 using std::string; 10 using std::vector; 11 using std::bitset; 12  13 int main() 14 { 15     const int iVar=10; 16     const int &iRef = iVar; 17     iRef = 20;  18     cout<<iVar<<endl; 19  20     return 0; 21 } 復制代碼     上面的程序編譯的結果如下所示:   [root@localhost cpp_src]# g++ test.cpp  test.cpp: In function ‘int main()’: test.cpp:17: 錯誤:assignment of read-only reference ‘iRef’ 可以發現在第17行,試圖對一個指向const對象的const引用賦值,結果編譯報錯。   復制代碼  1 #include <iostream>  2 #include <string>  3 #include <vector>  4 #include <bitset>  5   6 using std::cin;  7 using std::cout;  8 using std::endl;  9 using std::string; 10 using std::vector; 11 using std::bitset; 12  13 int main() 14 { 15     const int iVar=10; 16     const int &iRef = iVar; 17     iRef = 20; 18  19     int &iRef1 = iVar; 20     cout<<iVar<<endl; 21  22     return 0; 23 } 復制代碼 程序編譯結果如下:   [root@localhost cpp_src]# g++ test.cpp  test.cpp: In function ‘int main()’: test.cpp:17: 錯誤:assignment of read-only reference ‘iRef’ test.cpp:19: 錯誤:將類型為 ‘int&’ 的引用初始化為類型為 ‘const int’ 的表達式無效 我們發現在程序編譯的時候第19行也報錯啦,報錯的類型是: 將 類型int &的引用初始化類型const int的表達式無效。   2、字面值引用      可以定義const引用代表字面值。實例如下:   復制代碼 int main() {     int const &iRef = 100;     const string &strRef = "volcanol";     cout << iRef <<endl;     cout << strRef <<endl;       return 0; } 復制代碼 程序的執行結果如下:   [root@localhost cpp_src]# g++ test.cpp  [root@localhost cpp_src]# ./a.out  100 volcanol 上面的實例注意一點: 要對字面值定義別名引用,則必須將別名引用定義為const型的,否則將出現編譯錯誤。       二、指針     指針是什麼,有的地方說是指針是一個地址。這裡我們不對指針的復雜用法進行討論,如果想了解指針的復雜用法可以產考我在園子裡的另外一篇隨筆,鏈接地址   為:http://www.cnblogs.com/volcanol/archive/2011/06/05/2073042.html   1、指針的定義     在C++中定義指針,很簡單,在定義的變量的時候,在變量的前面加上一個 * 就表示要定義一個指針變量。語法如下:   指針要指向的數據類型  * 指針變量名; Exp:     int  *pInt;  定義了一個指向整型變量的指針變量pInt;     string *pStr;  定義了一個指向string類型的對象的指針pStr;     vector<int>  *pVectorInt; 定義一個指向vector<int> 容器的指針。      bitset<5>     *pBitset5;  定義一個指向bitset<5>類型的對象的指針。   2、指針變量賦值和初始化     指針變量在使用前必須有一個確定的指向,否則就會造成一個游離的指針,操作的游離指針會得到一個意想不到的的結果。通過取得一個變量的地址然後賦值給   指針變量或者初始化指針變量使指針變量有一個確定的指向。  通過操作符 & 取得一個變量/對象的地址或者(指針)。     指針變量初始化:         int  iVar = 10;       int  *pInt = &iVar;       指針變量賦值:         int iVar = 10;       int *pInt1;       int *pInt2;       pInt1 = &iVar;       pInt2 = pInt1;     3、指針的引用     通過解引用操作符 * 可以引用指針指向的變量。   復制代碼   int iVar = 20;     int *pInt = NULL;     pInt = &iVar;     cout<< * pInt<<endl; 復制代碼 Exp:   復制代碼 int main() {     int iVar = 100;     int *pInt = &iVar;     cout<<(*pInt)<<endl;       string strVar = "volcanol";     string *pStr = &strVar;     cout<<(*pStr)<<endl;       vector<int> vInt(1);     vector<int> *pVecInt=&vInt;     cout<<(*pVecInt)[0]<<endl;       bitset<5> bitVar(5);     bitset<5> *pBitset5 = &bitVar;     cout<< (*pBitset5) <<endl;       return 0; } 復制代碼 程序的執行結果如下所示:   [root@localhost cpp_src]# g++ test.cpp  [root@localhost cpp_src]# ./a.out  100 volcanol 0 00101 要點:     在定義指針變量的時候,必須在每個指針變量的前面都加上 * ,否則定義的就是一個非指針變量。     int  *pInt1,pInt2; //pInt1 為指針變量,  pInt2為整型變量。     在定義指針變量的時候,有兩種風格的格式:   int  *pInt 和  int*  pInt; 這兩種格式沒有對錯之分,兩種格式C++都是接受的,只是在理解的時候可能會引起   誤解。為了避免誤解,在一個程序裡面,最好選取一種格式一直保持下去。           4、指針的指針     指針變量也是一種對象,同樣可以給指針變量定義一個指向它的指針,就是指針的指針。定義語法如下:       指針的指針變量指向的對象類型  **指針的指針變量標識符;   Exp:     int iVar = 10 ;     int *pInt = &iVar;     int **ppInt = &pInt; 如上就定義了一個指向整型指針變量的指針變量ppInt;   ppInt指向的對象的類型為 int* 類型的對象。   復制代碼 int main() {     int iVar = 100;     int *pInt = &iVar;     int **ppInt = &pInt;       cout <<"iVar ="<< iVar<<endl;     cout <<"int *pInt = &iVar,then *pInt ="<<*pInt<<endl;     cout <<"int **ppInt = &pInt,then *ppInt="<<*ppInt;     cout <<";and then **ppInt="<<**ppInt<<endl;       return 0; } 復制代碼 程序的執行結果如下所示:   [root@localhost cpp_src]# g++ test.cpp  [root@localhost cpp_src]# ./a.out  iVar =100 int *pInt = &iVar,then *pInt =100 int **ppInt = &pInt,then *ppInt=0xbfb949f8;and then **ppInt=100     5、通過指針訪問數組元素     這裡需要說明一個細節:  某一個數組的數組名是一個常量,而且數組名表示的是數組的第一個元素的首地址,同時數組元素在內存中是連續存放的。   正是因為數組具有上述的特點,才能方便的通過指針來訪問數組的元素。     通過指針訪問數組元素的例子如下:   復制代碼 int main() {     int iArray[5] = {1,2,3,4,5};     int *pInt = iArray;       cout << *pInt << endl;  // 1     cout << pInt[0]<<endl;  // 1     cout << *++pInt<<endl;  // 2     cout << *pInt++<<endl;  // 2     cout << *pInt<<endl  ;  // 3       return } 復制代碼 程序的執行結果如下所示:   [root@localhost cpp_src]# ./a.out  1 1 2 2 3 不但可以通過++運算符來改變指針的指向,指針還支持加整數和減整數運算,同時支持兩個指針的減法運算。   復制代碼 int main() {     int iArray[5] = {1,2,3,4,5};     int *pInt1 = iArray;     int *pInt2= &iArray[4];       cout <<*(pInt1 + 2)<<endl;  // 3     cout <<*(pInt2 - 1)<<endl;  // 4     cout << pInt2 - pInt1 <<endl;       return 0; } 復制代碼 程序的執行結果如下:   [root@localhost cpp_src]# g++ test.cpp  [root@localhost cpp_src]# ./a.out  3 4 4 要點:     可以發現這個地方  pInt2 - pInt1 的結果是4, 這個結果與C語言的輸出是存在差別的。這一點要非常注意,在指針與數組結合使用的過程中,兩個指針相減   是經常見到的操作,因此這個地方需要注意。          通過上面的實例,我們可知利用指針可以很方便的訪問數組的元素,因此我們可以通過指針遍歷整個數組。   復制代碼 int main() {     int iArray[5] = {1,2,3,4,5};       for(int *pBegin=iArray,*pEnd=iArray+5; pBegin != pEnd; ++pBegin)         cout<<*pBegin<<endl;       return 0; } 復制代碼 程序的執行結果如下所示:   復制代碼 [root@localhost cpp_src]# g++ test.cpp  [root@localhost cpp_src]# ./a.out  1 2 3 4 5 復制代碼   指針和數組之間的定義還包括* 和 [] 符號同時在定義中出現的情況,   Exp:   復制代碼  1 #include <iostream>  2 #include <string>  3 #include <vector>  4 #include <bitset>  5   6 using std::cin;  7 using std::cout;  8 using std::endl;  9 using std::string; 10 using std::vector; 11 using std::bitset; 12  13 int main() 14 { 15     int iArray_1[5] = {1,2,3,4,5}; 16     int iArray_2[3] = {1}; 17     int *pInt1[5] ={iArray_1, iArray_2}; 18     int (*pInt2)[5] = iArray_1; //error 19     pInt2 = iArray_2;   //error  20  21  22     return 0; 23 } 復制代碼      上面的代碼中, 我標出了兩處錯誤,錯誤的原因是, pInt2 是一個二維的指針,而iArray_1 和 iArray_2 都是int * 類型的指針, 如果將程序修改一下就可以   得到如下的結果。   復制代碼  1 #include <iostream>  2 #include <string>  3 #include <vector>  4 #include <bitset>  5   6 using std::cin;  7 using std::cout;  8 using std::endl;  9 using std::string; 10 using std::vector; 11 using std::bitset; 12  13 int main() 14 { 15     //int iArray_1[5] = {1,2,3,4,5}; 16     //int iArray_2[3]= {1}; 17     //int *pInt1[5] ={iArray_1, iArray_2}; 18     //int (*pInt2)[5] = iArray_1; //error 19     //pInt2 = iArray_2;   //error  20  21     int iArray_1[5]={1,2,3,4,5}; 22     int iArray_2[3][5]={{1}}; 23     int iArray_3[5][3]={{2}}; 24     int (*pInt)[5] = iArray_2; 25     pInt=iArray_3;  //error  26  27  28     return 0; 29 } 復制代碼 上面的代碼中,我們可以知道  25行的語法是錯誤的,錯誤的原因是二維數組的第二維的指針長度不一致。通過上面的例子我們可以知道,* 和 [] 在一起定義指針變量   的時候,需要注意 * 和 [] 符號的優先級,同事需要知道加上括號後,定義的時候[] 的維度的擴展。這個地方是C語言當中經常會使用的,而且是屬於較復雜的用法,因   此需要因此特別的重視。       6、 指針 和 const限定符/修飾符     指針和const的結合使用沒有太多的說頭,主要是注意const修飾的 *p 還是 p, 只要分清楚修飾對象的不同就很好理解。   復制代碼 int main() {     int iVar1 = 10;     int iVar2 = 20;     const int *pInt1 = &iVar1;     int const *pInt2 = &iVar1;     int * const pInt3 = &iVar1;     const int * const pInt4 = &iVar1;     int const * const pInt5 = &iVar2;         return 0; } 復制代碼   關於const限定符需要知道的就是上面的各個定義的意義,只要知道 const是修飾 *pInt 還是修飾pInt就可以准確的分辨各個定義的意義,具體可以關注我前面   給出的關於C語言趣事相關的鏈接文章。     這裡還有一個需要注意的地方,就是對於const對象如何定義指向其的指針,下面是一個例子:   復制代碼 int main() {     const int iVar = 10;     //int *pInt1 = &iVar;  //error       int const *pInt1 = &iVar;     const int *pInt2 = &iVar;       return 0; } 復制代碼   這裡要注意加了注釋部分錯誤的原因。這裡就不解釋了,這個與const對象與引用的關系是一樣的。       7、指針和typedef的使用     在C語言中進程會做這樣的預處理指令。   #define  PINT  int*   這樣定義宏以後,就可以通過這個宏來定義指針變量,如下所示:   #define PINT int*   int iVar = 0; PINT pInt = &iVar;   這樣是可以通過的,但是這樣會存在一個漏洞,如果同時定義兩個指針變量的話,就會出現錯誤。   #define  PINT int*   int iVar1 = 0; int iVar2 = 0; PINT pInt1 = &iVar1,  pInt2 = &iVar2;     很顯然上面的代碼存在漏洞,  第二個變量 pInt2 不是指針變量,而是一個整型的變量, 好在這樣的錯誤編譯器在編譯的時候會檢查出來,這裡需要引起注意。       我們可以利用typedef機制來規避上述的風險,  typedef 的作用就是為數據類型取一個別名,尤其在數據類型比較長時是一個非常有效的機制, typedef的語法   如下:     typedef   數據類型   數據類型別名;   例如:     typedef  int*  PINT;   這就為 int* 這種類型定義了一個新的別名 PINT,在使用的時候PINT就表示 int*。   Exp:   typedef  int*  PINT;   int iVar1 = 0; int iVar2 = 0; PINT pInt1 = &iVar1,  pInt2 = &iVar2;   上面的代碼定義了兩個整型變量 iVar1、iVar2, 同時定義了兩個指針變量pInt1 和 pInt2;    要點:     通過上面兩個例子,就可以清楚 typedef和#define 之間的差別。        注意typedef是語句,因此後面必須有個分號結尾。  這個點是經常容易忘記的,好在編譯器一般可以檢測出這樣的錯誤。          typedef和指針的結合還有一個值得注意的地方,就是 typedef 、const和指針同時出現。   typedef  int* PINT const PINT pInt;  //error   這裡定義的指針對象pInt是const指針對象, 這個指針對象在定義的時候必須初始化。因此要注意上面的這個錯誤。   復制代碼  1 #include <iostream>  2 #include <string>  3 #include <vector>  4 #include <bitset>  5   6 using std::cin;  7 using std::cout;  8 using std::endl;  9 using std::string; 10 using std::vector; 11 using std::bitset; 12  13 int main() 14 { 15     typedef int* PINT; 16     const PINT pInt; 17  18     return 0; 19 } 復制代碼 程序編譯的結果如下所示:   [root@localhost cpp_src]# g++ test.cpp  test.cpp: In function ‘int main()’: test.cpp:16: 錯誤:未初始化的常量 ‘pInt’ 將程序改成下面的形式則正確:   復制代碼 #include <iostream> #include <string> #include <vector> #include <bitset>   using std::cin; using std::cout; using std::endl; using std::string; using std::vector; using std::bitset;   int main() {     typedef int* PINT;     //const PINT pInt;     int iVar = 0;     const PINT pInt = &iVar;  //初始化const指針       return 0; } 復制代碼   當然還可以定義更加復雜的數據類型,這裡就不再進行描述,後面如果碰到會進行相關的描述。         指針的操作基本上就是這些,在C++語言中,大部分的人傾向於不使用指針, 但是指針確實是一種非常高效的機制,但是如果能把指針用好,則會對   程序的性能的提升具有很好的提高作用。 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved