第2章 2 3復合型別

2021-09-12 07:15:26 字數 4598 閱讀 9224

2.3.2 指標

2.3.3 理解符合型別的宣告

復合型別是指基於其他型別定義的型別。c++有幾種符合型別,其中兩種為:引用、指標

2.3.1 引用

引用為物件起了另外乙個名字,引用型別引用另外一種型別。通過將宣告符寫成 &d 的形式來定義引用型別,其中 d 是宣告的變數名:

int a = 1024;

int &b = a; // b指向a(實際上,b是a的另外乙個名字,它們表示的是同乙個物件)

int &b; // 報錯:引用必須被初始化

一般在初始化變數時,初始值會被拷貝到新建的物件中。然而定義引用的時候,程式是把引用和它的初始值繫結在一起,而不是將初始值拷貝給引用。一旦初始化完成,引用將和它的初始值物件一直繫結在一起,因此無法令引用重新繫結到另外乙個物件,因此引用必須初始化

【引用即別名】

引用並非物件,它只是為乙個已經存在的物件所起的另外乙個名字。

​ 定義了乙個引用後,對其進行的所有操作都是在與之繫結的物件上進行的:

int a = 1;

int &b = a;

b = 2; // 即把2賦給b所指向的物件,即把2賦給了a

int c = b; // 相當於執行 c = a

int &d = b; // 相當於將d繫結到了b繫結的物件上,即繫結到a上

int e = b; // e被初始化為a的值

因為引用本身不是乙個物件,所以不能定義引用的引用。

【引用的定義】

​ 允許在一條語句中定義多個引用,其中每個引用識別符號都必須以符號 & 開頭:

int i = 1, i2 = 2;        // i 和 i2 都是int

int &r = i, r2 = i2; // r是乙個引用,與i繫結;r2是int

int i3 = 1024, &ri = i3; // i3是int,ri是乙個引用,與i3繫結

int &r3 = i3, &r4 = i2; // r3 和 r4 都是引用

​ 除了一些特殊情況外,引用的型別都要和與之繫結的物件嚴格匹配。另外,引用只能繫結在物件上,不能與字面值或某個表示式的計算結果繫結在一起

int &i = 10;      // 錯誤:引用型別的初始值必須是乙個物件

double k = 3.14;

int &j = k; // 錯誤:此處引用型別的初始值必須是個int型物件

2.3.2 指標

指標是「指向」另外一種型別的復合型別。定義指標型別的方法是將宣告符寫成 *d 的形式,其中d是變數名。如果在一條語句中定義了幾個指標變數,那麼每個指標變數前都必須有符號 *:

int *p1, *p2;    // p1 和 p2 都是指向int型物件的指標

double *d1, d2; // d1是指向double型物件的指標,d2是double型物件

【指標和引用的區別】

​ 與引用類似,指標也實現了對其他物件的間接訪問。然而,指標和引用相比又有很多不同點:

(1)指標本身就是乙個物件,允許對指標賦值和拷貝,並且在指標的生命週期裡它可以先後指向多個不同的物件;

(2)指標無須在定義的時候賦初值。與其它內建型別一樣,在塊作用域內定義的指標如果沒有被初始化,也將擁有乙個不確定的值。

【獲取物件的位址】

int i = 42;

int *p = &i; // p存放變數i的位址

在宣告語句中,指標的型別實際上被用於指定它所指向物件的型別,因此除了一些特殊情況外,指標的型別要和它所指向的物件嚴格匹配:

double a;

double *b1 = b; //正確:初始值是指向double物件的指標

int *c = b; //錯誤:指標c的型別和a的型別不匹配

【注意】因為引用不是物件,沒有實際位址,因此不能定義指向引用的指標。

【利用指標訪問物件】

​ 如果指標指向了乙個物件,則允許使用**解引用符(操作符*)**來訪問物件。對指標解引用會得出所指的物件,因此如果給解引用的結果賦值,實際上就是給指標所指的物件賦值:

int a = 1;

int *b = &a;

cout << *b; //會輸出 1

*b = 2; //相當於為a賦值2

cout << a; //輸出 2

【空指標】

空指標不指定任何物件,在試圖使用乙個指標前**可以首先檢查它是否為空。下列幾種方法都可以生成空指標:

int *ptr1 = nullptr;    // 等價於 int *ptr1 = 0;

int *ptr2 = 0; // 直接將p2初始化為字面值常量0

int *ptr3 = null; // 等價於 int *ptr3 = 0;

​ 得到空指標最直接的辦法就是用字面值nullptr來初始化指標,這是c++11新標準剛引入的一種方法。nullptr是一種特殊型別的字面值,它可以被轉換成任意其它指標。另一種辦法就是通過將指標初始化為字面值0來生成空指標。

​ 過去的程式會用到乙個名為null預處理變數來給指標賦值,這個變數在標頭檔案cstdlib中定義,它的值就是0。在程式中,當用到乙個預處理變數時,預處理器會自動地將它替換為實際值,因此用null初始化指標和用0初始化指標是一樣的。但是在新標準下,最好使用nullptr,而不要用null。另外,把int變數直接賦給指標是錯誤的操作,即使這個int變數的值正好是0:

int i = 0;

int *ptr = i; // 錯誤:不能把int變數的值直接賦給指標

【賦值和指標】

​ 引用本身並不是乙個物件,一旦定義了引用,就無法令其再繫結其它的物件,之後每次使用這個引用都是訪問其最初繫結的那個物件。然而,指標和它存放的位址之間並沒有這種限制,和其他任何變數一樣,給指標賦值就是令它存放乙個新的位址,從而指向乙個新物件:

int i = 1;

int *ptr = 0; // ptr被初始化,但沒有指向任何物件

int *ptr1 = &i; // ptr1被初始化,存有i的位址

int *ptr2; // 如果ptr2定義於塊內,則ptr2的值無法確定

ptr2 = ptr1; // ptr2 和 ptr1指向同乙個物件i

ptr1 = 0; // 現在ptr1不指向任何物件

​ 要搞清楚一條賦值語句到底是改變了指標的值還是改變了指標所指物件的值,最好的辦法就是記住賦值永遠改變的是等號左側的物件。例如:

int i = 0;

int *ptr;

ptr = &i; // ptr的值被改變,現在ptr指向了i

*ptr = 2; // i的值被改變,而ptr沒變

【void* 指標】

void指標是一種特殊的指標型別,可以用於

double a = 3.14, *ptr = &a;

pv = ptr; // 正確:void*能存放任意型別的指標

【注意】利用void指標能做的事情比較有限:拿它和其他指標比較、作為函式的輸入或輸出,或者賦給另外乙個void指標。不能直接操作void*指標所指的物件,因為我們並不知道這個物件的型別到底是什麼,也就無法確定能在這個物件上進行什麼操作。

2.3.3 理解符合型別的宣告

【指向指標的引用】

​ 指標是物件,因此存在對指標的引用:

int i = 42;

int *p; // p是乙個int型指標

int *&r = p; // r是乙個對指標p的引用

r = &i; // r引用了乙個指標,因此給r賦值&i就是令p指向i

*r = 0; // 將i的值改為0

​ 要搞清楚r是什麼型別,最簡單的辦法就是從右向左閱讀r的定義。離變數名最近的符號(此例中是&r的符號&)對變數的型別有最直接的影響,因此r是乙個引用。宣告符的其餘部分用以確定r引用的型別是什麼,此例中的符號*說明r引用的是乙個指標。最後,宣告的基本資料型別是int,因此引用的是int型的指標。

第4章 復合型別

第 4 章 復合型別 一 陣列 潛規則 只有在定義陣列時才能使用初始化。不能將乙個陣列賦給另乙個陣列。如果初始化為,則表示第乙個元素被設定為1,其他元素被設定為0。二 字串 注意要點 在確定儲存字串所需的最短陣列時,記得將結尾的空字元計算在內。如果要顯示部分字串,只需將需要的字串的結尾標記為 0 每...

C primer plus 第4章 復合型別

1.陣列初始化 2.字串 兩種方式 c 風格字串 以 0結尾 string類庫 單引號表示字元常量 a 是字串編碼的簡寫,char a a 是正確的。但是 a 表示的是兩個字元a和 0組成的字串,實際上 a 表示的是字串所在的記憶體位址,因此char a a 是非法的 1 cin.getline a...

2 3復合型別 指標

指標是 指向 另外一種型別的復合型別。與引用類似,指標也實現了對其他物件的間接訪問。但兩者有很多不同 1.指標本身是乙個物件,允許對指標複製和拷貝,而且在指標的生命週期內它可以先後指向幾個不同的物件 2.指標無須在定義時賦初值和其他內建型別一樣,在塊作用域內定義的指標如果沒有初始化,也將有乙個不確定...