C++基礎筆記——彙總版(上)
前言: 部落格開始記錄了一系列C++筆記,但各章節太分散,且編輯格式不是很規範,不便於檢視;現把各章節做一個彙總,準備放在一起,方便按知識點檢視。彙總版的C++基礎筆記包括上、下兩部分。
程式的組成部分
C++是面向物件程式設計,有如下特點。1.封裝、2.繼承和重用、3.多型
1.封裝,C++支援通過建立使用者自定義的型別來封裝屬性,這種型別稱為類。定義好的一個類是一個完全封裝的實體,可以使用整個實體,也可以不使用。
2.繼承和重用,C++通過繼承來支援重用的概念。可將新型別宣告為現有型別的擴充套件,新子類稱為繼承了現有型別。
3.多型,C++使用了稱為函式多型和類多型的功能,多型指的是同一樣東西有多種形態。
程式一般由以下4個部分組成:
1.前處理器編譯指令:前處理器相當於編譯前的程式碼編輯,每條編譯指令都是一個命令,編譯指令#include<…>告訴前處理器,將指定檔案的全部內容加入到程式的指定位置。C++提供了一個標準原始碼庫,可以在程式中使用它們來執行有用的功能。
2.原始碼行:每個C++程式都包含一個main()函式,程式執行時將自動呼叫main(),這和C語言一樣。函式都以左大括號{開始,以右大括號}結束。
3.註釋:使原始碼的功能顯而易見,可分為單行註釋和多行註釋;單行註釋以兩個斜槓(//)打頭,只註釋當前行;而多行註釋以斜槓和星號/ *
打頭,並以星號和斜槓*/
結尾,在/*
和*/
之間的所有內容都會被註釋,不管它佔據多少行。另外,關於多行註釋,需要注意的是,不能巢狀,如:/*....../*......*/....*/
4.函式:函式由函式頭和函式體組成,其中函式頭包含三部分:函式的返回型別,函式名,函式接受的引數。當函式不返回值時,使用返回型別void,表示空;函式名是一個簡短的識別符號,描述了函式的功能;引數是當呼叫這個函式時,傳遞給這個函式的資料。程式從main()開始執行,並逐行執行原始碼,當呼叫函式時,程式將轉而執行該函式,函式執行完畢後,將返回到呼叫函式的程式碼行,函式可能返回值,也可能不返回值,但main()函式是一個例外,它總是返回一個整數。return語句導致函式結束,如果函式不包含return語句,將自動在函式體末尾返回void。在這種情況下,必須將函式的返回型別指定為void。
變數和常量
1、變數
變數是計算機記憶體中的一個位置,可以從這裡儲存和檢索值。在C++中,當建立變數時,必須將變數的名稱和儲存的資訊型別(如整數、字元或浮點數)告訴編譯器,這就是變數的型別,有時也稱為資料型別。通過變數的型別,編譯器將知道需要預留多少記憶體空間,以儲存變數的值。可以使用函式sizeof(),變在括號內指定型別名,獲得變數型別的長度。
所有整型變數都又分為兩種型別,無符號變數和有符號變數。除整型變數以外,C++還支援浮點數型別和字元。浮點變數可儲存包含小數的值,而字元變數佔用1位元組,可儲存ASCII字符集中的256個字元和符號之一。
定義變數要遵從變數名的命名規則,變數名可包含任何大小寫字母、數字、下劃線,但不能包含空格。
注意:C++區分大小寫。C++保留了一些單詞,不能將它們作為變數名,因為它們是C++使用的關鍵字。關鍵字如:if、while、for、main等,在程式設計時,字型會變色,很容易區分。
要給變數賦值,可使用運算子=,它被稱為賦值運算子。
型別定義:當C++程式包含大量變數時,不斷輸入unsigned short既繁瑣又容易出錯,要建立現有型別的簡潔表示,可使用關鍵字typedef,它表示型別定義(type definition)。
如:typedef unsigned short USHORT
這條語句建立了一個名為USHORT的型別定義,可在程式的任何地方使用它來代替unsigned short。
2、常量
與變數一樣,常量也是一個記憶體位置,可在其中儲存值;不同的是,常量的值會改變,C++支援兩種型別的常量:字面常量和符號常量。字面常量是直接在需要的地方輸入的值。如:long width=5
;符號常量是用名稱表示的常量,宣告符號常量時,需要用關鍵字const,並在後面跟型別、名稱和初始值。如:const int KILL_BONUS=5000
;
定義常量,可使用編譯指令#define來建立常量,這種方法起源於早期的c語言版本。如:#define KILLBONUS 5000
,這種常量不需要指定型別,編譯指令#define執行簡單的文字替換,將程式碼中的KILLBOUNS都替換成5000,編譯器只能看到替換後的結果。
列舉常量:在一條語句中建立一組常量,它們是使用關鍵字enum定義的,後面跟一組用逗號分隔的名稱,這些名稱放在大括號內,如:enum COLOR{ RED,BLUE,GREEN,WHITE,BLACK}
;這條語句建立了一組名為COLOR的列舉常量,其中包含5個名為RED,BLUE,GREEN,WHITE,BLACK的值。列舉常量值以0(對應於第一個常量)打頭,其他常量依次加1,也可以使用賦值運算子指定列舉常量的值,如:enum COLOR{ RED=100,BLUE,GREEN=500,WHITE,BLACK=700}
;這條語句將RED設定為100,將GREEN設定為500,將BLACK設定為700,對於沒有設定值的列舉常量,其值比它前面的成員大1,即BLUE為101,而WHITE為501。
表示式、語句、運算子
1、語句
所有C++都是由語句組成,語句是以分號結尾的命令。每條語句可獨佔一行也可以將多條語句放在一行,只要每條語句都以分號結尾即可。
在C++程式的原始碼中,空格、製表符和換行符統稱為空白。空白旨在讓程式設計師方便閱讀程式碼,編譯器通常忽略它們。另外,注意,變數名不能包含空白。
2、表示式
表示式是語句中任何返回一個值的部分。如:z=x=y+13;
這條語句包含三個表示式:1、表示式y+13,其值被儲存在變數x中。2、表示式x=y+13,它返回變數x的值,而該返回值被儲存在變數z中。3、表示式z=x=y+13,它返回變數z的值,但該返回值沒有儲存到其他變數中。
3、運算子
運算子是導致編譯器執行操作的符號,如賦值=
、執行乘法運算*
、除法運算/
或其他數學運算。
3.1 賦值運算子
賦值運算子由賦值運算子、左運算元和右運算元組成,如:grade=95,注意:賦值=
不等於等號==
。
3.2 數學運算子
數學運算子有五個:加法+
、減法-
、乘法*
、除法/
和求模%
(也叫求餘)運算子。注意:它和C語言一樣,沒有乘方運算子。
3.3 組合運算子
一個變數與一個值操作,並將結果賦給這個變數。組合運算子有自賦值加法運算子+=
、自賦值減法運算子-=
、自賦值除法運算子/=
、自賦值乘法運算子*=
和自賦值求模運算子%=
。如:score+=10;與score = score + 10;等價。
3.4 遞增遞減運算子
遞增運算子(++)和遞減運算子(–)是將變數加1和減1。
這裡有個區別就是運算子是放在變數名前面和放在變數名後面的區別,它們之間的效果不一樣。
如++count(字首運算子)和count++(叫做字尾運算子)之間的區別。它們在簡單語句的效果相同,都是將變數count加1。但是,如在下面這例子中就可以看到二者的區別了:int x=5; int sum=++x;和int x=5; int sum=x++;在兩個中,x最後的值都是6,但sum的值卻不一樣,第一個是6,第二個是5。
3.5 關係運算符
關係運算符用於比較,以判斷一個數是大於、等於或小於另一個數,返回的結果為true或者是false。關係運算符有相等(==)、不等(!=)、大於(>)、大於等於(>=)、小於(<)、小於等於(<=)。
3.6 邏輯運算子
通過邏輯運算子,可測試多個條件,返回結果也是true或者false。邏輯與運算子(&&):連線兩個表示式,當它們都為true時,結果為true。邏輯或運算子(||):連線兩個表示式,當它們兩個有一個為true時,結果為true。非運算子(!):對錶達式求反,當表示式為false時,結果為true。
注意:在C++中0被認為是false,而其他值被認為是true。所以負數也被認為是true。
呼叫函式
函式是程式的一部分,可對資料執行操作並返回一個值,每個C++程式至少有一個函式:程式執行時自動呼叫的main()。這個函式可包含呼叫其他函式的語句,而這些函式中也可能呼叫其他函式。
在編寫函式的程式碼前,必須宣告它。函式宣告將函式的名稱、函式返回型別和函式輸入引數的型別告訴編譯器。函式宣告也叫原型,不包含任何程式碼,是單條語句,以分號結尾。引數列表列出了所有引數及其型別,並用逗號將他們分開。如: int findArea(int length, int width);函式可返回任何C++資料型別,如果函式不返回值,就應該將返回型別宣告為void。
區域性變數:在函式內建立的變數稱為區域性變數,因為它只存在於函式中,當函式返回後,其所有區域性變數都不能供程式使用。區域性變數的建立方式與其他變數相同,函式收到的引數也被視為區域性變數。
全域性變數:在函式(包括函式main())外面定義的C++變數,這樣的變數稱為全域性變數。它在程式的任何地方都可用。注意:在編碼的過程中應該多用區域性變數,少用全域性變數,因為它們會導致錯誤難以查詢。
函式的返回值,在同一個函式中,可包含多條return語句。
預設函式引數,如果函式有多個引數,將根據引數的順序指定預設值。可給任何引數指定預設值,但有一項需注意:如果某個引數沒有預設值,那麼它前面的任何引數都不能有預設值。
函式過載,返回引數型別相同,函式名相同,輸入引數不同(引數的型別不同或引數數量不同都可),這樣的函式稱為函式過載。如:int store(int ,int);和int store(long, long);和int store(long);函式過載也被稱為函式多型。
行內函數,如果函式包含的語句很少,就可以通過避免跳轉來提高效率,在這種情況下,通過避免函式呼叫,程式的執行速度將更快。在宣告C++函式時,如果使用了關鍵字inline,編譯器將不會建立該函式,而將程式碼直接複製到呼叫它的地方,就像在呼叫它的地方直接輸入了函式的語句一樣。 如:inline int double(int);關鍵字inline提示編譯器,你希望將該函式嵌入在呼叫它的地方。
注意:
在函式內部對引數進行修改時,不會影響到呼叫它的函式。因為,在預設情況下,引數是按值傳遞的,這意味著函式接受的引數實際上是原始值的備份,即使變數名相同也一樣。
int findArea(int width,int length =1);
int findArea(int size);這是同一個函式的兩個不同過載版本的宣告,宣告將能通過編譯,但是如果使用一個引數呼叫了findArea(),就將出現編譯錯誤,指出無法確定應該呼叫findArea(int,int)還是findArea(int)。
控制程式流程
while迴圈不斷執行一個程式碼塊,直到條件不再為true。如果條件永遠不為true,程式碼塊一次也不會執行。
相反,do-while迴圈會執行程式碼塊一次,即使檢查的條件永遠不為true。
for迴圈包含初始化部分、檢查部分和操作部分。這些部分使得可在for語句中建立計數器變數以及檢查和修改該變數的值。
使用continue和break語句可編寫出複雜迴圈,continue語句直接進入下一次迴圈迭代,而break語句結束整個迴圈。
switch語句讓檢查同一個變數的多種可能取值變得更簡單,雖然使用一系列if和if-else條件也可以實現這樣的目標,但switch語句更容易開發和除錯。注意,在switch語句中,總是應該包含default部分,即使沒有理由使用它,這是一種良好的程式設計習慣。可使用default部分顯示一條錯誤訊息,它表明表示式的值出乎意料,不與任何case部分相匹配。另外,每一個case部分的結尾都應該新增break語句。
使用陣列和字串儲存資訊
陣列是一系列型別相同的相關資料,可將陣列視為一系列資料儲存單元,其中每個儲存單元都是陣列的一個元素。
要宣告陣列,可依次指定資料型別、陣列名以及用方括號括起來的元素數,如:long peaks[25]
;陣列元素的編號也稱為下標,陣列元素從0開始編號,所有上例中,元素的下標最大為24。
字元陣列,字串是一系列字元,在C++中,字串是以空字元結尾的字元陣列,空字元是編碼為‘\0’的特殊字元。可像其他陣列那樣宣告並初始化字串:
char yum[ ] = {'z','o','m','b','i','e',' ','e','a','t',' ','b','r','a','i','n','s','\0'}
;
最後用’\0‘空字元來結束字串的輸入。也可以用簡潔的方式:char yum[ ]="zombie eat brains"
;這種初始化方法不需要使用空字元,而是由編譯器自動新增。字串"zombie eat brains"佔用18個位元組(包括空字元在內),即一個字元佔用一個位元組。
C++從C語言那裡繼承了一個處理字串的函式庫,要將這個庫加入到程式中,可包含標頭檔案string.h。#include <string.h>
建立基本類
前面書中介紹的內容和C語言的差不多,從這一章開始才是真正意義上的C++部分的學習。
在C++中,可以自己定義型別,以模擬要解決的問題。但是要宣告一個新型別,就得建立一個類,類是新型別的定義。
C++類是一個模板,可用於建立物件。定義類後,便可以像使用其他型別那樣使用它建立的物件。類是一系列捆綁在一起的變數和函式,其中的變數也可以包括其他型別或者其他類。將變數和函式捆綁在一起稱為封裝。通過封裝,可以讓其他程式能夠使用類,而無需知道他的工作原理。類中的變數稱為成員變數,類中的函式可以使用或修改成員變數,它們被稱為類的成員函式或方法。
要宣告類,可使用關鍵字class,並在後面加上有關成員變數和成員函式的資訊。如:
class Tricycle
{
public:
unsigned int speed;
unsigned int wheelSize;
pedal();
brake();
};
上述程式碼建立一個Tricycle類,注意,上述宣告不會給Tricycle類分配記憶體,只有建立了物件才會分配記憶體,建立物件的方法是:Tricycle Wichita;這條語句就建立了一個名為wichita的Tricycle物件。
建立物件後,可使用句點運算子(.)類訪問其成員函式和成員變數。如:wichita.speed或者呼叫成員函式wichita.pedal();
對於剛剛宣告的類的成員函式,都必須定義,也叫做實現。成員函式的定義以類名打頭,然後是作用域解析運算子(::)和函式名,如:
void Tricycle ::pedal()
{
std::cout << "Pedaling trike\n";
}
類有兩個特殊的函式,建構函式和解構函式,前者是每次例項化物件時都將呼叫它,建構函式與類同名,且沒有返回值。而後者是負責執行清理工作並釋放分配給物件的記憶體。解構函式的名稱總是由顎化符號(~)和類名組成的,解構函式不接受任何引數,也不返回值。在使用者沒有宣告建構函式或者解構函式的情況下,編譯器會自動提供預設建構函式或解構函式,它們沒有引數且函式體都為空,不執行任何操作。
高階類
常量成員函式:在宣告的類中,被關鍵字const所修飾的成員函式就叫做常量函式,這表明它不會修改任何類成員變數的值。如果將函式宣告為常量函式,但其實現修改了成員變數的值,編譯器就將報錯。如:
class Tricycle
{
public:
int speed =6;
void setSpeed( int speed) const
{
speed++; //修改成員變數的值,編譯器會報錯
}
}
組織類宣告和函式定義
在C++程式的原始碼中,類的定義和實現通常是分開的。一般情況下,我們將類的宣告放在標頭檔案中,其檔名與原始碼檔案相同,但副檔名為.hpp(或不那麼常見的.h或.hp)。如:我將Tricycle類的宣告放在檔案Tricycle.hpp中,那麼類函式的定義將放在位於Tricycle.cpp中,通過使用預處理編譯器指令,可在.cpp檔案中包含標頭檔案:#include "Tricycle.hpp"
,將它們分開的原因是,使用類的使用者不需要關心類實現的細節。
最後一點,在建立複雜類時,經常將簡單類作為其成員變數。這在上一章也提到過。
建立指標
指標,在c語言中也存在,這一章提到的內容也和c語言中的差不多。大家都知道,變數是可儲存一個值的物件,整型變數儲存一個數字,字元變數儲存一個字母,而指標變數就是儲存記憶體地址的。當要獲取一個記憶體的地址資訊,可以使用地址運算子&。
在指標中儲存地址
如果將指標初始化為0或NULL,以後必須將變數的地址賦值給它,如:
int age = 40;
int *page = 0;
page = &age; //把age變數的地址賦值給指標變數page。
這裡順便講一下間接訪問,它是指訪問指標儲存的地址處的值,指標提供了一種間接獲取值的方式。間接運算子*
也被稱為解除引用運算子。對指標解除引用時,將獲取指標儲存的地址處的值。接上例:int yourage = age
;和int yourage = *page
;是一個意思,指標page前面的間接運算子*
表示“儲存在…處的值”,這條賦值語句的意思是從page指向的地址處獲取值,並將它賦值給yourage。
指標最常用於完成如下三項任務:管理堆中的資料,訪問類的成員資料和成員函式,按引用將變數傳遞給函式。
棧和堆
程式設計師通常需要處理如下5個記憶體區域:全域性名稱空間,堆,暫存器,程式碼空間和棧。區域性變數和函式引數儲存在棧中,程式碼儲存在程式碼空間中,而全域性變數儲存在全域性名稱空間中,暫存器用於管理記憶體,如跟蹤棧頂和指令指標。幾乎餘下的所有記憶體都分配給了堆,堆有時也被稱為自由儲存區。每當函式返回時,都會清理棧,而只有到程式結束後才會清理堆,因此使用完預留的記憶體後,需要負責將其釋放。讓不再需要的資訊留在堆中稱為記憶體洩露。
堆的優點在於,在顯示釋放記憶體前,預留的記憶體始終可用。如果在函式中預留堆中的記憶體,在函式返回後,該記憶體仍然可用。
在C++中,要分配堆中的記憶體,可使用關鍵字new,並在它後面指定要為之分配記憶體的物件的型別,好讓編譯器知道需要多少記憶體。關鍵字new返回一個記憶體地址,必須將其賦值給一個指標。如:
int *pPointer;
pPointer = new int;
*pPointer = 72; //將72賦給pPointer指向的堆記憶體區域
使用完分配的記憶體區域後,必須對指標呼叫delete,將記憶體歸還給堆。因為指標是區域性變數,這不同於它指向的堆記憶體,當宣告指標的函式返回時,指標不在作用域中,因此被丟棄,然而,使用new運算子分配的堆記憶體不會自動釋放,這些記憶體將不可用,這就被稱為記憶體洩露。要將記憶體歸還給堆,可使用關鍵字delete,如:delete pPointer
;刪除指標時,實際上是釋放了其地址儲存在指標中的記憶體,這被稱為將指標指向的記憶體歸還給了堆。指標還是指標,可重新給他賦值。刪除指標時,應將其設定為NULL。注意:程式中的每個new呼叫都必須有對應的delete呼叫,應跟蹤哪個指標指向了記憶體區域,並在使用完後將記憶體釋放。
開發高階指標
前面一章講到怎樣在堆中分配記憶體,這一章主要講怎樣在堆中建立物件(例項化類的物件),其原理是一樣的,同樣是利用關鍵字new,delete。如:
當定義了型別Cat後,便可宣告一個指向這種物件的指標,並在堆例項化一個Cat物件,語法如下:Cat *pcat = new Cat
;這將呼叫預設建構函式----不接受任何引數的建構函式。對指向堆中物件的指標呼叫delete時,將呼叫物件的解構函式,然後釋放記憶體。
使用指標訪問資料成員
對於在棧中建立的Cat物件,可使用句點運算子(.)來訪問其成員資料和成員函式;要訪問堆中的Cat物件,必須對指標解除引用,並對指標指向的物件使用句點運算子。因此,要訪問成員函式Getage(),可編寫如下程式碼:(*pcat).Getage();
也可以使用間接訪問運算子:指向運算子(->),上句程式碼可變為:pcat->Getage();
this指標
每個類成員函式都有一個隱藏的引數:this指標,它指向相應的物件。this指標儲存了當前物件的記憶體地址,可成為功能強大的工具。通常,在成員函式中,無需使用this指標來訪問當前物件的成員變數,但如果願意,可以顯式地使用this指標。
懸擺指標
懸擺指標是導致bug的罪魁禍首之一,對指標呼叫delete後,如果沒有重新賦值就使用它,將導致懸擺指標。懸擺指標又稱野指標或迷失指標。
const指標
宣告指標時,可在型別前、型別後或兩個地方使用const關鍵字。如:
const int *pOne; //pOne指向整型常量的指標,即使用該指標不能修改它指向的值
int * const pTwo; //pTwo是指向整型的常量指標,可修改指向的整型變數,但pTwo不能指向其他變數,不能給常量指標重新賦值
const int * const pThree; //pThree是一個指向整型常量的常量指標,不能修改它指向的值,也讓它指向其他變數。
如果聲明瞭一個指向常量物件的指標,那麼使用該指標只能呼叫常量函式。將物件宣告為常量時,實際上是將this宣告為指向常量物件的指標,常量this指標只能用於呼叫常量成員函式。
建立引用
這一章主要講引用,其用處和前面講的指標差不多,但用法要比指標容易些,總的來講,引用就是一個變數的別名。建立引用時,使用另一個物件(目標)的名稱來初始化它,從此以後,該引用就像是這個目標的另一個名稱,對引用執行的任何操作實際上針對的就是目標。指標和引用的區別就是:指標是儲存另一個物件的地址的變數,而引用是物件的別名。
建立引用
要建立引用,需要指定目標物件的型別、引用運算子(&)和引用名。如:int &rSomeRef = someint
;這句語句的含義是,rSomeRef是一個int引用,被初始化為指向someint。
如果聲明瞭引用但沒有初始化,就將導致編譯器出錯,引用必須初始化。注意:這裡的引用運算子(&)和前面所講的地址運算子(&)是同一個符號,根據程式的上下文區分。
將地址運算子用於引用如:
int &rSomeRef = intone;
std ::cout <<&intone; //輸出變數intone的地址
std ::cout <<&rSomeRef; //也會輸出變數intone的地址,而不是rSomeRef的地址
在C++中,無法獲取引用本身的地址,因為它不像指標或其他變數的地址那樣有意義。引用是在建立時初始化的,總是目標的同義詞,通常,在使用引用時,不將地址運算子用於它,而像使用目標變數那樣使用引用,不能給引用重新賦值,他始終是目標變數的別名。
可引用的目標
可引用任何物件,包括使用者自己定義的物件。注意:我們建立的是指向物件的引用,而不是指向類或資料型別(如int)的物件。所以以下程式碼是錯的:
int &rIntRef = int; //錯誤
應該改為:
int age=20;
int &rIntRef = age;
同樣,當我們自己建立了cat類後,這些程式碼也是錯的:
cat &rCatRef = cat; //錯誤
應該改為:
cat Frisky;
cat &rCatRef = Frisky;
可以像使用物件那樣使用指向物件的引用:訪問成員資料和成員函式,使用類成員訪問運算子(.),如:rCatRef.age
,rCatRef.voice()
等。
空指標和空引用
指標未初始化或被刪除時,應將NULL賦給它,但對於引用來說,引用不能為空,讓引用指向空物件的程式是非法的。
按引用傳遞函式引數
在第五章講到,函式的引數是按值傳遞(物件值的備份)的,返回的結果不能修改原來的值,但按引用傳遞的方式就不同了,它有兩種方式:使用指標和使用引用。他們的語法不同,但效果相同:不是在函式作用域內建立物件值的備份,而是將原始物件傳遞給函式。通過按引用傳遞物件,可讓函式修改指向的物件。使用指標,傳遞的實際上是物件的地址,因此函式可直接操作該地址處的值。
如果函式是使用指標傳遞引數,則呼叫函式時,引數為變數的地址(如:&i);如果函式是是使用引用傳遞引數,則呼叫函式時,引數為變數(如:i)。
高階引用和指標
前面講到,每次按值將物件傳入函式時,都將建立該物件的一個備份。每次按值從函式返回一個物件時,也將建立其備份。對於使用者建立的大型物件,備份的代價很高。這將增加程式佔用的記憶體量,而程式的執行速度也將會變慢。按引用傳遞避免了建立備份以及呼叫複製建構函式,所以它的效率會更高。
但有一個非常重要的問題是,雖然將指標傳遞給函式的效率更高,但很危險。如果不想要函式修改物件的值,即要同時獲得按值傳遞的安全性和按引用傳遞的效率,就必須傳遞一個指向物件的const指標,這可以禁止對物件呼叫任何非常量成員函式,從而禁止修改該物件。
什麼情況下使用引用以及什麼情況下使用指標
一般而言,C++程式設計師更喜歡使用引用而不是指標,因為它們更清晰,使用起來更容易。然而,引用不能重新賦值,如果需要依次指向不同的物件,就必須使用指標。引用不能為NULL,因此如果要指向的物件可能為NULL,就必須使用指標,而不能使用引用。如果要從堆中分配動態記憶體,也要使用指標。
程式在堆中分配記憶體時,將返回一個指標。必須一直讓某個指標指向這塊記憶體,因為指標丟失後,便無法釋放該記憶體,進而導致記憶體洩露。如果我們要編寫這樣的函式,即它需要分配記憶體塊並將其傳遞給呼叫它的函式,應該考慮修改介面:讓發出呼叫的函式分配記憶體,然後按引用將其傳遞給被呼叫的函式,這樣,便可以做到在哪個函式中分配記憶體,就在哪個函式中釋放記憶體了。
問:為何要從函式按值返回?
答:如果返回的是區域性物件,即在這個函式中所定義的物件(除去在堆中所定義的物件),必須按值返回,否則返回的引用將指向不存在的物件。