C++中關於指針入門的最好的文章

什麼是指針?

    其實指針就像是其它變量一樣,所不同的是一般的變量包含的是實際的真實的數據,而指針是一個指示器,它告訴程序在內存的哪塊區域可以找到數據。這是一個非常重要的概念,有很多程序和算法都是圍繞指針而設計的,如鏈表。

    開始學習

    如何定義一個指針呢?就像你定義一個其它變量一樣,只不過你要在指針名字前加上一個星號。我們來看一個例子:下面這個程序定義了兩個指針,它們都是指向整型數據。

    int* pNumberOne;

    int* pNumberTwo;

    你注意到在兩個變量名前的“p”前綴了嗎?這是程序員通常在定義指針時的

    一個習慣,以提高便程序的閱讀性,表示這是個指針。現在讓我們來初始化這兩個指針:

    pNumberOne = &some_number;pNumberTwo = &some_other_number;

    &號讀作“什麼的地址”,它表示返回的是變量在內存中的地址而不是變量本身的值。在這個例子中,pNumberOne 等於some_number的地址,所以現在pNumberOne指向some_number. 如果現在我們在程序中要用到some_number,我們就可以使用pNumberOne.

    我們來學習一個例子:

    在這個例子中你將學到很多,如果你對指針的概念一點都不瞭解,我建議你多看幾遍這個例子,指針是個很複雜的東西,但你會很快掌握它的。

    這個例子用以增強你對上面所介紹內容的瞭解。它是用C編寫的(注:原英文版是用C寫的代碼,譯者重新用C++改寫寫了所有代碼,並在DEV C++ 和VC++中編譯通過!)

 #include <iostream.h>
  
  void main()
  {
  // 聲明變量:
  
  int nNumber;
  int *pPointer;
  
  // 現在給它們賦值:
  
  nNumber = 15;
  pPointer = &nNumber;
  
  //打印出變量nNumber的值:
  
  cout<<"nNumber is equal to :"<< nNumber<<endl;
  
  // 現在通過指針改變nNumber的值:
  
  *pPointer = 25;
  
  //證明nNumber已經被上面的程序改變
  
  //重新打印出nNumber的值:
  
  cout<<"nNumber is equal to :"<<nNumber<<endl;
  }

    通讀一下這個程序,編譯並運行它,務必明白它是怎樣工作的。如果你完成了,準備好,開始下一小節。

    陷井!

    試一下,你能找出下面這段程序的錯誤嗎?

 #include <iostream.h>
  
  int *pPointer;
  
  void SomeFunction();
  
  {
  int nNumber;
  nNumber = 25;
  
  //讓指針指向nNumber:
  
  pPointer = &nNumber;
  }
  
  void main()
  {
  SomeFunction(); //爲pPointer賦值
  
  //爲什麼這裏失敗了?爲什麼沒有得到25
  
  cout<<"Value of *pPointer: "<<*pPointer<<endl;
  }

    這段程序先調用了SomeFunction函數,創建了個叫nNumber的變量,接着讓指針pPointer指向了它。可是問題出在哪兒呢?當函數結束後,nNumber被刪掉了,

    因爲這一個局部變量。局部變量在定義它的函數執行完後都會被系統自動刪掉。也就是說當SomeFunction 函數返回主函數main()時,這個變量已經被刪掉,但pPointer還指着變量曾經用過的但現在已不屬於這個程序的區域。如果你還不明白,你可以再讀讀這個程序,注意它的局部變量和全局變量,這些概念都非常重要。

    但這個問題怎麼解決呢?答案是動態分配技術。注意這在C和C++中是不同的。由於大多數程序員都是用C++,所以我用到的是C++中常用的稱謂。

    動態分配

    動態分配是指針的關鍵技術。它是用來在不必定義變量的情況下分配內存和讓指針去指向它們。儘管這麼說可能會讓你迷惑,其實它真的很簡單。下面的代碼就是一個爲一個整型數據分配內存的例子:

    int *pNumber;

    pNumber = new int;

    第一行聲明一個指針pNumber.第二行爲一個整型數據分配一個內存空間,並讓pNumber指向這個新內存空間。下面是一個新例,這一次是用double雙精型:

    double *pDouble;pDouble = new double;

    這種格式是一個規則,這樣寫你是不會錯的。

    但動態分配又和前面的例子有什麼不同呢?就是在函數返回或執行完畢時,你分配的這塊內存區域是不會被刪除的所以我們現在可以用動態分配重寫上面的程序:

 #include <iostream.h>
  
  int *pPointer;
  
  void SomeFunction()
  {
  
  // 讓指針指向一個新的整型
  
  pPointer = new int;
  *pPointer = 25;
  }
  
  void main()
  {
  SomeFunction(); // 爲pPointer賦值
  
  cout<<"Value of *pPointer: "<<*pPointer<<endl;
  }

    通讀這個程序,編譯並運行它,務必理解它是怎樣工作的。當SomeFunction調用時,它分配了一個內存,並讓pPointer指向它。這一次,當函數返回時,新的內存區域被保留下來,所以pPointer始終指着有用的信息,這是因爲了動態分配。但是你再仔細讀讀上面這個程序,雖然它得到了正確結果,可仍有一個嚴重的錯誤。

        分配了內存,別忘了回收

    太複雜了,怎麼會還有嚴重的錯誤!其實要改正並不難。問題是:你動態地分配了一個內存空間,可它絕不會被自動刪除。也就是說,這塊內存空間會一直存在,直到你告訴電腦你已經使用完了。可結果是,你並沒有告訴電腦你已不再需要這塊內存空間了,所以它會繼續佔據着內存空間造成浪費,甚至你的程序運行完畢,其它程序運行時它還存在。當這樣的問題積累到一定程度,最終將導致系統崩潰。所以這是很重要的,在你用完它以後,請釋放它的空間,如:delete pPointer;

    這樣就差不多了,你不得不小心。在這你終止了一個有效的指針(一個確實指向某個內存的指針)。

    下面的程序,它不會浪費任何的內存:

 #include <iostream.h>
  
  int *pPointer;
  
  void SomeFunction()
  {
  
  // 讓指針指向一個新的整型
  
  pPointer = new int;
  *pPointer = 25;
  }
  
  void main()
  {
  SomeFunction(); //爲pPointer賦值
  
  cout<<"Value of *pPointer: "<<*pPointer<<endl;
  
  delete pPointer;
  }

    只有一行與前一個程序不同,但就是這最後一行十分地重要。如果你不刪除它,你就會製造一起“內存漏洞”,而讓內存逐漸地泄漏。(譯者:假如在程序中調用了兩次SomeFunction,你又該如何修改這個程序呢?請讀者自己思考)

    傳遞指針到函數

    傳遞指針到函數是非常有用的,也很容易掌握。如果我們寫一個程序,讓一個數加上5,看一看這個程序完整嗎:

 #include <iostream.h>
  
  void AddFive(int Number)
  {
  Number = Number + 5;
  }
  
  void main()
  {
  int nMyNumber = 18;
  
  cout<<"My original number is "<<nMyNumber<<endl;
  AddFive(nMyNumber);
  cout<<"My new number is "<<nMyNumber<<endl;
  
  //得到了結果23嗎?問題出在哪兒?
  
  }

    問題出在函數AddFive裏用到的Number是變量nMyNumber的一個副本而傳遞給函數,而不是變量本身。因此, " Number = Number + 5" 這一行是把變量的副本加了5,而原始的變量在主函數main()裏依然沒變。試着運行這個程序,自己去體會一下。要解決這個問題,我們就要傳遞一個指針到函數,所以我們要修改一下函數讓它能接受指針:把'void AddFive(int Number)' 改成 'void AddFive(int*Number)' 。下面就是改過的程序,注意函數調用時要用&號,以表示傳遞的是指針:

  #include <iostream.h>
  void AddFive(int* Number)
  {
  *Number = *Number + 5;
  }
  
  void main()
  {
  int nMyNumber = 18;
  
 cout<<"My original number is "<<nMyNumber<<endl;
  AddFive(&nMyNumber);
  cout<<"My new number is "<<nMyNumber<<endl;

}

本文來自:http://c.chinaitlab.com/cc/basic/200903/780269.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章