程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
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++語言中,大部分的人傾向於不使用指針, 但是指針確實是一種非常高效的機制,但是如果能把指針用好,則會對

程序的性能的提升具有很好的提高作用。 

  

 

 

  關於指針和引用暫時就說到這, 接下來將要對C語言風格和C++風格的字符串進行一番討論, 待續......


本人14歲,正在自學C語言,已經學完了C PRIMER PLUS,簡單看了一下C與指針,教下一該學什?

HACKER的話,C語言稍微學習下就好了。

網絡多接觸下,比如,網絡的拓撲結構,網絡安全,計算機操作系統,socket通信(c/c++裡面也有不少這方面的范例),還有就是windows命令行以及linux的命令,再者可以深造一下ASM(匯編),現在的話,php也是很不錯的,做HACKER還是要掌握一下的。

想深入學習c的話,推薦《C++ PRIMER》,數據結構的話,可以了解一下。我是常年開發c++應用的,所以比較懶了,數據結構和算法都直接用C++的STD庫了,自己也省事兒,當然你也能拿STD庫來參考學習。

指針還是很有用,也是要用心學習的。做的時間久了,可以用用boost庫,當然現在也可以看看,主要看那些前輩們怎麼實現一些復雜的功能的。
 

自學電腦編程 除了《C Primer Plus》《C程序設計語言》《C與指針》《C專家編程》等書 數學以外還要學什

既然是電腦編程,那麼VC6.0還是不錯的。做幾個小游戲練練手。然後再理解一下《軟件工程》,面試個工作,然後就可以了。
單純的C語言一般應用到unix和單片機中的比較多,windows中感覺很少了,除非一些歷史遺留的傳統項目。
所以還是向C++或Java或。。。發展吧。
 

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