引用與指標
1、引用
引用(reference)為物件起了另外乙個名字,引用型別引用(refer to)另外一種型別。通過將宣告符寫出&d的形式來定義引用型別,其中d是宣告的變數名。
一般在初始化變數時,初始值會被拷貝到新建的物件中,然後定義引用時,程式把引用和它的初始值繫結在一起,而不是將初始值拷貝給引用。一旦初始化完成,引用將和它的初始值一直繫結在一起。因為無法令引用重新繫結到另外乙個物件,因此引用必須初始化。
引用即別名。引用並非物件,相反的,它只是為乙個已經存在的物件所起的另外乙個名字。
int val = 1024;
int &refval1 = val; //refval指向val(是val的另外乙個名字)
int &refval2; //報錯:引用必須初始化
定義乙個引用之後,對其進行的所有操作都是在與之繫結的物件上進行的。為引用賦值,實際上是把值賦給了與引用繫結的物件;獲取引用的值,實際上是獲取了與引用繫結的物件的值;以引用作為初始值,實際上是以與引用繫結的物件作為初始值。
refval1 = 2; //把2賦給refval1所指向的物件,此處即賦給了val
int ii = refval1; //ii被初始化為val的值,與ii = val;執行結果相同
int &refval3 = refval1; //refval3繫結到了那個魚refval1繫結的物件上,即繫結到val上
因為引用本身不是乙個物件,所以不能定義引用的引用。
允許在一條語句中定義多個引用,其中每個引用識別符號都必須以&開頭。
幾乎所有引用的型別都要和與之繫結的物件嚴格匹配。
引用只能繫結在物件上,不能與字面值或某個表示式的計算結果繫結到一起。
int i = 1024, i2 = 2048; //i和i2都是int
int &r = i, r2 = i2; //r是乙個引用,與i繫結到一起,r2是乙個int
int i3 = 1024, &r3 = i3; //i3是int,r3是乙個引用,與i3繫結在一起
int &r3 = i3, &r4 = i2; //r3和r4都是引用
int &refval4 = 10; //錯誤:引用型別的初始值必須是乙個物件
double dval =3.14;
int &refval5 = dval; //錯誤:此處引用型別的初始值必須是int型物件
2、指標
定義:指標(pointer)是指向(point to)另外一種型別的復合型別。定義指標的型別的方法是將宣告符寫成*d的形式,其中d是變數名。如果在一條語句中定義了多個指標變數,每個變數前面都必須有符號。
int *ip1, *ip2; // ip1和ip2均為指向int型物件的指標
double dp, **dp2; //dp2為指向double型物件的指標,dp為double型物件
獲取物件的位址
指標存放某個物件的位址,獲取該位址需要使用取位址符(&)
在宣告語句中指標的型別實際上被用於指定它所指向物件的型別,所以除了兩種型別意外,其他所有指標的型別都要和它所指向的物件型別嚴格匹配。
因為引用不是物件,沒有實際的位址,所以不能定義指向引用的指標。
int ival = 42, &ref = ival;
int *p = &ival; //p存放變數ival的位址,或者說p是指向變數ival的指標
double dval;
double *pd = &dval; //初始值double型別物件的位址
double *pd2 = pd; //初始值是指向double物件的指標
int *pi = pd; //錯誤:指標pi的型別和pd的型別是不匹配的
指標的值
指向乙個物件
指向緊鄰物件所佔空間的下乙個位置
空指標,意味著沒有指向任何物件
無效指標,也就是上述情況之外的其他值
試圖拷貝或以其他方式訪問無效指標將引發錯誤,編譯器不負責檢查此類錯誤。
第2和第3種形式的指標雖然有效,但是由於沒有指向任何具體物件,所以試圖訪問此類指標物件的行為也不被允許。
利用指標訪問物件
指標指向乙個物件,則允許使用解引用符(*)來訪問該物件。
對指標解引用會得到所指的物件,因此如果給解引用的結果賦值,實際上也就是給指標所指的物件賦值。
解引用操作僅適用於那些確實指向了某個物件的有效指標。
int ival = 42; //
int *p = &ival; //p存放著變數ival的位址,或者說p是指向變數ival的指標
cout << *p; //由符號*得到指標p所指的物件,輸出42
*p = 0; //由符號*得到p所指的物件,即可由p為變數ival賦值
在宣告語句中,&和
*用於組成復合型別,在表示式中,他們是運算子
空指標空指標不指向任何物件,在試圖使用乙個指標之前,可以先檢查乙個它是否為空。
生成空指標的方法:
int *p = nullptr; //等價於第二個,nullptr是一種特殊型別的字面值,可以被轉換成任意其他型別的指標。
int *p2 = 0; //直接將p2初始化為字面常量0
int *p3 = null; //null 為預處理變數,它的值就為0,需要首先#include cstdlib
把int
變數直接賦值給指標是錯誤的操作,即使int變數的值恰好等於0也不行。
int zero = 0;
pi = zero; //錯誤:不能把int變數直接賦給指標
和其他變數一樣,訪問未經初始化的指標所引發的後果是無法**的,通常這一行為將會造成程式崩潰。
賦值和指標
和其他非引用的任何變數一樣,給指標賦值就是令它存放乙個新的位址,從而指向乙個新的物件。
賦值永遠改變的是等號左側的物件。
int i = 42;
int *pi = 0; //pi被初始化,但是沒有指向任何物件
int *pi2 = &i; //pi2被初始化,存有i的位址
int *pi3; //如果pi3存放在塊內,則pi3的值無法確定
pi3 = pi2; //pi2與pi3指向同乙個物件i
*pi2 = 50; //pi2指向的i的值被改變,指標pi2並沒有改變
pi2 = 0; //pi2的值被改變,現在pi2不指向任何物件了
其他指標操作
只要指標擁有乙個合法值,就可以用在條件表示式中,和採用算術值作為條件遵循的規則類似。任何非0指標對應的條件值都是true,0指標條件去false。
對於兩個型別相同的指標,可以用相等操作符(==)和不相等操作符(!=)來比較她們,比較的結果是布林型別。
void*指標
void*是一種特殊的指標型別,可用於存放任意物件的位址,該位址中到底是個什麼型別的變數並不了解。
void*指標能做的事情很有限:和別的指標比較、作為函式的輸入或輸出、賦給另外乙個
void*
指標。
不能直接操作
void*
指標所指的物件。
指標與引用的區別
★ 相同點:
1. 都是位址的概念;
指標指向一塊記憶體,它的內容是所指記憶體的位址;引用是某塊記憶體的別名。
★ 區別:
1. 指標是乙個變數,而引用僅是個別名;
2. 引用使用時無需解引用(*),指標需要解引用;
3. 引用只能在定義時被初始化一次,之後不可變;指標可變;
4. 引用沒有 const,指標有 const,const 的指標不可變;
5. 引用不能為空,指標可以為空;
6. 「sizeof 引用」得到的是所指向的變數(物件)的大小,而「sizeof 指標」得到的是指標本身(所指向的變數或物件的位址)的大小;typeid(t) == typeid(t&) 恒為真,sizeof(t) == sizeof(t&) 恒為真,但是當引用作為成員時,其占用空間與指標相同(沒找到標準的規定)。
7. 指標和引用的自增(++)運算意義不一樣;
8. 如果返回動態記憶體分配的物件或者記憶體,必須使用指標,引用可能引起記憶體洩漏;
★ 聯絡
1. 引用在語言內部用指標實現(const 指標?)。
2. 對一般應用而言,把引用理解為指標,不會犯嚴重語義錯誤。引用是操作受限了的指標(僅容許取內容操作)。
指標與引用
摘自 高質量c 程式設計 指標與引用,在more effective c 的條款一有詳細講述,我給你轉過來 條款一 指標與引用的區別 指標與引用看上去完全不同 指標用操作符 和 引用使用操作符 但是它們似乎有相同的功能。指標與引用都是讓你間接引用其他物件。你如何決定在什麼時候使用指標,在什麼時候使用...
引用與指標
引用就是物件的另乙個名字,在實際的程式中,引用主要用作函式的形式引數。引用是一種復合型別,通過在變數名前新增 符號來定義。復合型別是指用其他型別定義的型別。在引用的情況下,每一種引用型別都 關聯到 某一其他型別。引用必須用與該引用同型別的物件初始化。當引用初始化後,只要該引用存在,它就保持繫結到初始...
指標與引用
include iostream using namespace std void testref int i 10 引用不可以為空,他是乙個物件的別名 int ref i ref cout i 00824f1e mov dword ptr i 1 把i的位址傳入eax 並把eax指標的位址傳給re...