Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 12 Pointers and Dynamic Arrays. Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 2 Overview Pointers (12.1) Dynamic Arrays.

Similar presentations


Presentation on theme: "Chapter 12 Pointers and Dynamic Arrays. Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 2 Overview Pointers (12.1) Dynamic Arrays."— Presentation transcript:

1 Chapter 12 Pointers and Dynamic Arrays

2 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 2 Overview Pointers (12.1) Dynamic Arrays (12.2) Classes and Dynamic Arrays(12.3)

3 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 3 12.1 Pointers ( 指標 ) 指標的內容是變數的記憶體地址 記憶體地址可拿來當做變數的名稱 假如一個變數需要 3 個記憶體空間 ( 一般是以 byte 為單 位 ), 則第 1 個記憶體空間的地址可當作該變數的名稱 當一個變數被用來當作 call-by-reference 的參數時, 其 實就是傳遞其記憶體地址

4 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 4 Pointers Tell Where To Find A Variable 指標就是用來告訴程式設計師某個變數在記憶體的 地址 指標透過地址告訴程式設計師一個變數儲放在哪裡,所 以說指標 指向 (“point” to) 一個變數

5 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 5 Declaring Pointers 指標變數必須宣告成含有 * Example: 下例宣告指向一個 double 變數的指標 : double *p; ‘*’ 標示變數 p 是一個指標

6 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 6 Multiple Pointer Declarations 要在一個宣告中宣告多個指標,在每個指標前加上 ‘*’ Example: int *p1, *p2, v1, v2; p1 and p2 指向 type int 的變數 v1 and v2 是 type int 的變數

7 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 7 The address of Operator ‘&’ 運算子可用來得到某變數之記憶體地址,該結 果可以給指向該變數資料型態的指標 Example: p1 = &v1; 執行後, p1 指向 v1 v1 也可以被稱為 “p1 指過去的變數 "

8 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 8 The Dereferencing Operator ( 提領:去 除記憶體地址 ) C++ 使用 ‘*’ 運算子處理指標的另一個做法 “p 指過去的變數 ” 在 C++ 中可以用 *p 表示 ‘*’ 在這種狀況就是 提領 (dereferencing) 運算子 p 在這種狀況就是被提領了 (dereferenced)

9 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 9 這列執行後, v1 及 *p1 為相同變數 A Pointer Example v1 = 0; p1 = &v1; *p1 = 42; cout << v1 << endl; cout << *p1 << endl; 輸出 : 42 42

10 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 10 Pointer Assignment 指定運算子 ( = ) 可用在指標上 Example: 如果 p1 指向 v1 ,則 p2 = p1; 會使 *p2, *p1, 及 v1 都是同一變數的不同名稱

11 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 11 Display 12.1 Caution! Pointer Assignments 使用指標變數來進行指定 (assignment) 時要特別 注意以下的不同 p1= p3; // 改變 p1 指向之記憶體地址 *p1 = *p3; // 改變 p1 指向之記憶體地址裡的值

12 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 12 The new Operator 使用指標時, 即使沒有變數名稱也能改變該指標指 向之記憶體裡的值 下例新增一個指向整數 (int) 之無名變數的指標 : p1 = new int; 這個變數可以用 *p1 來處理 ( 存取其值 ) *p1 可用於任何 integer 變數可以出現的地方 cin >> *p1; *p1 = *p1 + 7;

13 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 13 使用 new 運算子產生的變數叫做 動態變數 (dynamic variables) 動態變數 在程式執行時才會被新增其記憶體空間 或 送 回給作業系統 Display 12.2 有 pointers and dynamic variables 更多範例 Display 12.2 程式碼的解說在 Display 12.2 Display 12.3 Dynamic Variables

14 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 14 new and Class Types new 運算子用於類別 (class) 資料型態時會呼叫建構子 (constructor) 並配置記憶體給該物件 如果 MyType 是一個類別 class 資料型態, 則 MyType *myPtr; // 產生指向一個 MyType 物件 // 的指標 myPtr = new MyType; // 呼叫 MyType 預設建構子 myPtr = new MyType (32.0, 17); // 呼叫 Mytype(double, int) 建構子

15 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 15 Basic Memory Management 記憶體中有一塊區域叫做自由儲存區 ( the freestore ) ,表示尚未配置給任何變數的記憶體區 域,預留給在程式執行時所新增的動態變數 新增的動態變數會使用 freestore 的記憶體 如果 freestore 全部被用光了, new 的呼叫就會失敗 不再需要的動態變數所佔用之記憶體可以回收至 freestore 當程式不再使用一個變數時, 該變數可被 delete 掉, 該 變數所使用的記憶體就會回到 freestore

16 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 16 The delete Operator 當程式不再需要一個變數時, 可以刪除 (delete) 他 以將記憶體回收至 freestore Example: delete p; 執行後, p 的值 ( 記憶體地址 ) 就是未定義 (undefined) , 且原來 p 所指向之記憶體就回收至 freestore

17 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 17 Dangling Pointers 使用 delete 於一指標變數 摧毀掉該變數所指向之 動態變數 如有另一指標變數指向該動態變數, 則該指標變數 也會變成未定義 (undefined) 未定義之指標變數也叫做 dangling pointers ( 晃蕩 指標 ) 提領 (dereference) 一個 dangling pointer (*p) 通常會使 程式當掉

18 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 18 Automatic Variables 函式中宣告的變數所需的記憶體空間,通常在執行 到該函式時會被新增,當程式離開該函式時,該函 式所新增的記憶體空間會被回收 這些可稱為自動變數, 因為他們的新增與回收是由執行 程式自動控制 程式設計師必須運用 new 及 delete 手動控制指標 變數的新增及回收

19 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 19 Global Variables 在所有函式外面宣告之變數被稱為全域變數 全域變數可在程式任何地方使用 ( 包括在函式內 ) 全域變數一般很少用

20 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 20 Type Definitions 一個名稱可以用來定義新的資料型態, 該名稱之後 就能用來宣告變數 關鍵字 typedef 就是用來定義新的資料型態的名稱 語法 : typedef Known_Type_Definition New_Type_Name; Known_Type_Definition 可以是任何資料型態

21 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 21 Defining Pointer Types 為避免使用指標時的錯誤, 可以定義一個指標資料 型態 Example: typedef int* IntPtr; 定義一個新的資料型態, IntPtr, 給指向 int 變數的指標 之後, 以下兩個宣告有相同意義 IntPtr p; int *p;

22 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 22 Multiple Declarations Again 使用以下的新資料型態 IntPtr : typedef int* IntPtr; 可避免宣告兩指標變數時,犯了以下的宣告錯誤 : int *P1, P2; // 只有 P1 是指標變數, P2 不是 // 指標變數 改用以下宣告 IntPtr P1, P2; // P1 and P2 都是指標變數

23 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 23 Pointer Reference Parameters 使用 typedef 的第 2 個好處是在函數的參數定義 Example: void sample_function(IntPtr& pointer_var); 比下例清楚 void sample_function( int*& pointer_var);

24 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 24 Section 12.1 Conclusion Can you Declare a pointer variable? Assign a value to a pointer variable? Use the new operator to create a new variable in the freestore? Write a definition for a type called NumberPtr to be a type for pointers to dynamic variables of type int? Use the NumberPtr type to declare a pointer variable called my_point?

25 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 25 12.2 Dynamic Arrays 動態陣列指陣列的大小必須於程式執行時才知道, 無法於程式設計時就知道其大小。

26 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 26 Pointer Variables and Array Variables 陣列變數其實就是指向陣列第一個元素的指標變數 Example: int a[10]; typedef int* IntPtr; IntPtr p; a and p 為相同種類之變數 因為 a 是指向 a[0] 的指標變數 p = a; 會使 p 與 a 指向相同的變數 ( a[0] )

27 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 27 Display 12.4 Pointer Variables As Array Variables 反方向來說,指標變數也可以當陣列變數來使用 Example: p[0], p[1], …p[9] 都符合 C++ 的語法 變數 a 可以當作指標來使用,但是 a 的指標值 ( 即其記憶體地址 ) 不能被異動 以下不符合 C++ 的語法 : IntPtr p2; … // p2 is assigned a value a = p2 // attempt to change a

28 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 28 Creating Dynamic Arrays 一般陣列的大小在程式設計師寫程式時就知道 但假設程式設計師預估的值太大 ? 程式執行時浪費記憶體 但假設程式設計師預估的值太小 ? 某些狀況下,程式可能無法執行 動態陣列就是要在程式執行時給程式剛好大小的陣 列,不會太大,也不會太小

29 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 29 動態陣列是用 new 運算子產生 Example: 下例產生一個含 10 個 double 元素之動 態陣列 : typedef double* DoublePtr; DoublePtr d; d = new double[10]; 這樣 d 就可以如一般陣列一樣使用 ! 這可以是一個 integer 變數 ! Creating Dynamic Arrays

30 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 30 ( 接上頁 ) d 這個指標變數指向 d[0] 當程式不再需要這個陣列, 這個陣列應該要回收至 freestore Example: delete [ ] d; 中括號 [ ] 告訴 C++ 一個動態陣列要被回收刪除了,因此 C++ 會檢查此動態陣列的大小以了解應該要回收多少個元素 如果忘了加上 [ ] ,仍然為合法的 C++ 語法,但 C++ 會只回收 陣列第 1 個元素 Display 12.5 (1) Display 12.5 (2) Dynamic Arrays (cont.)

31 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 31 Pointer Arithmetic 陣列所代表的記憶體地址可以執行加減運算 以 double 動態陣列, d, 為例, 再提醒一次 d 指向 d[0] 運算式 d+1 為 d[1] 的地址, d+2 為 d[2] 的地址 注意加 指標 +1 會讓 指標加上該變數所需之記憶體的大小

32 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 32 Pointer Arithmetic Operations 指標的加加減減 ++ and - - 運算子可用於指標 相同資料型態的兩個變數的指標可以拿來相減,可以得 到這兩個指標間的元素個數 注意此兩個變數必須在同一陣列 下例顯示指標的加減 : for (int i = 0; i < array_size; i++) cout << *(d + i) << “ ” ; // 與 cout << d[i] << “ ” ; 同樣的意思

33 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 33 Multidimensional Dynamic Arrays 以下為產生一個 3x4 二維整數動態陣列 ( 相同方法 可擴充至更高維動態陣列 ) 的注意事項 視多維動態陣列 為 以陣列為基底 的陣列 ( 上層 ) 首先產生一個 “ 基底為整數指標 ” 之一維動態陣列 先定義 整數指標 的新資料型態 : typedef int* IntArrayPtr; 再定義其動態陣列 m: IntArrayPtr *m = new IntArrayPtr[3]; ( 底層 ) 其次,對 m 中的每一個指標, 產生一個整數的動 態陣列 for (int i = 0; i<3; i++) m[i] = new int[4];

34 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 34 m IntArrayPtr's int's IntArrayPtr * A Multidimensional Dynamic Array 上頁的二維動態陣列圖示如下 :

35 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 35 刪除多維動態陣列的方法 ( 先回收底層,再回收上 層 ) 每一個呼叫 new 所產生的動態陣列都需要一個對應的 delete[ ] 呼叫 Example: 以下刪除上頁之二維動態陣列 : for ( i = 0; i < 3; i++) delete [ ] m[i]; // 先刪除底層的整數動態陣列 delete [ ] m; // 再刪除 IntArrayPtr 動態陣列 Display 12.6 (1)Display 12.6 (2) Deleting Multidimensional Arrays

36 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 36 Section 12.2 Conclusion Can you Write a definition for pointer variables that will be used to point to dynamic arrays? The array elements are of type char. Call the type CharArray. Write code to fill array "entry" with 10 numbers typed at the keyboard? int * entry; entry = new int[10];

37 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 37 12.3 Classes and Dynamic Arrays 動態陣列的基礎資料型態可以是類別 如 Watch *p; X=10; p = new Watch[x]; 一個類別可以有 動態陣列的 成員變數 StringVar 就是一個範例.

38 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 38 Program Example: A String Variable Class 我們將定義 StringVar 類別 StringVar 物件是用來代表字串 StringVar 物件使用字元動態陣列,其大小必須在執行 程式時才知道 StringVar 類別與 11-2 的 string 類別功能相似

39 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 39 The StringVar Constructors StringVar 預設建構子 產生一個代表空字串的 StringVar 物件,此字串最大長度設為 100 ( 註: 因為此字串可能變長,因此需預留空間 ) StringVar 第 2 個建構子需要一個 int 的參數,來 決定此空字串物件以後之最大長度值 StringVar 第 3 個建構子需要一個 C-string 的參數以 … 將該 C-string 的長度設為此字串之可能最大長度 將該 C-string 複製到此字串之內部動態陣列變數上

40 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 40 Display 12.7 (1)Display 12.7 (2) The StringVar Interface 除了建構子, StringVar 的介面包括 : 成員函式 : int length( ); void input_line(istream& ins); friend ostream& operator << (ostream& outs, const StringVar& the_string); Copy 建構子 …( 晚點再討論 ) Destructor 解構子 …( 晚點再討論 )

41 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 41 Display 12.8 A StringVar Sample Program 使用 StringVar 在 Display 12.7 的介面 我們可以寫一使用 StringVar 類別之程式 此程式內的 conversation 函式可以: 產生 2 個 StringVar 物件, your_name 及 our_name your_name 的字串最長可達 max_name_size our_name 初始值為 “Borg” ,只能改變為不大於 4 個字元的字串

42 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 42 Display 12.9 (1) Display 12.9 (2) The StringVar Implementation StringVar 使用一個字元動態陣列來存放代表該字 串的字元們 StringVar 建構子呼叫 new 為成員變數 value 產生動態 字元陣列 value 要用 ‘\0’ ( 虛字元 ) 來中止字串 ( 請參考 11-1) 此陣列之大小必須等到程式執行 new 時才會知道 建構子的參數 ( 不論是 預設建構子、一個整數參數之建構子、 一個字串參數之建構子 中任一個 ) 會決定其大小

43 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 43 Dynamic Variables 只有呼叫 delete 運算子,動態變數 ( 及陣列 ) 才能回 收 即使一個區域指標變數在函式結束後自動回收, 該指標 所指向的動態變數 ( 及陣列 ) 會留在程式中,除非呼叫 delete 將其回收 但是使用 SringVar 類別的程式設計師不可能知道 StringVar 是用了一動態陣列作為其私有成員變數,所 以當程式不再需要一個 StringVar 物件時,不會也不能 呼叫 delete 來回收動態陣列

44 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 44 Destructors 解構子是一個成員函數,當該類別的物件離開其有 效範圍時 ( 如函式結束時、 for 迴圈結束時等等 ) , 解構子會被自動呼叫 解構子必須含有將建構子產生的動態陣列回收的程式碼 一個類別僅需要一個不用任何參數的解構子 解構子的宣告就是在預設建構子前加上 ~ Example: ~StringVar( );

45 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 45 ~StringVar StringVar 的解構子必須呼叫 delete [ ] 來回收動態陣列的記憶體空間至自由儲 存區 (the freestore) Example: StringVar::~StringVar( ) { delete [ ] value; }

46 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 46 Display 12.10Display 12.11 Pointers as Call-by-Value Parameters 在函式呼叫時,將指標 (pointers) 作為 call-by- value 的參數會產生沒有預期到的結果 記得參數 (parameters) 是函式的區域變數 在函式內改變參數 (parameter) 的值,不會造成引數 (argument 即呼叫函式的變數 ) 的值跟著改變 參數的值設為引數 (argument) 的值,當引數為指標時其 值為一記憶體地址 因此參數及引數有相同之值 ( 即指標指向之記憶體之地址 ) 如果參數用來改變其地址指向之記憶體內容, 因為引數指 向之記憶體即為參數指向之記憶體,因此引數指向之記 憶體內容也改變了,如 Display 12.10, 12.11 所示

47 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 47 Copy Constructors 如果不想造成上頁的副作用 ( 即用指標變數做引數 呼叫 call-by-value 的函式參數,可以改變此指標 變數指向的變數的值 ) ,可用 複製 (copy) 建構子 幫忙解決 複製建構子的參數之資料型態即為該類別 此參數必須為 call-by-reference 此參數通常是一個 constant 參數, ( 不改變引數物件的 內容 ) 此建構子產生一個完整且獨立的引數複製物件,讓引數 物件與該新生物件不會糾纏在一起

48 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 48 StringVar Copy Constructor StringVar 之複製建構子程式碼如下: 產生一個新的動態陣列準備來放字串的字元 將引數的字串 ( 即動態字元陣列 ) 複製到此物件剛產生的 動態字元陣列 StringVar::StringVar(const StringVar& string_object) : max_length(string_object.length() ) { value = new char[max_length+ 1]; strcpy(value, string_object.value); }

49 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 49 Calling a Copy Constructor 在宣告該類別的物件時,複製建構子與其他建構子 的呼叫方式相同 複製建構子在以下狀況會被自動呼叫 宣告時,當其引數為相同類別的物件 當一個函式傳回一個該類別的值 ( 即物件 ) 當一個 call-by-value 參數以該類別的物件作為引數呼叫

50 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 50 The Need For a Copy Constructor 假設沒有複製建構子,下例顯示在引數呼叫時,會 有什麼問題 void show_string(StringVar the_string) { …} StringVar greeting("Hello"); show_string(greeting); cout << greeting << endl; 當呼叫 show_string(greeting) 時, greeting 被複製到參 數 the_string the_string.value 被設為與 greeting.value 相同

51 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 51 greeting.value the_string.value "Hello" The Need For a Copy Constructor (cont.) 因為 greeting.value 及 the_string.value 都是指標, 他們指向同一動態陣列

52 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 52 greeting.value the_string.value Undefined The Need For a Copy Constructor (cont.) 當 show_string 執行結束時, the_string 的解構子會自動被 執行, 將 the_string.value 指向之動態陣列回收至自由儲存 區 ( the freestore) 這時 greeting.value 指向的記憶體已經被回收至自由儲存 區 ( the freestore)

53 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 53 The Need For a Copy Constructor (cont.) Greeting 這個 StringVar 物件有 2 個問題 輸出 greeting.value 很可能會出現錯誤 有時 OK ,但不能靠運氣 當離開 greeting 的有效範圍時, 他的解構子會自動被呼叫 同一記憶體地址被解構子呼叫回收 2 次會造成系統錯誤 (system crashing error)

54 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 54 greeting.valuethe_string.value "Hello" Copy Constructor Demonstration 當有了複製建構子,上面的問題就不會發生了 greeting.value 及 the_string.value 指向記憶體不同位置

55 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 55 greeting.valuethe_string.value "Hello" undefined Copy Constructor Demonstration (cont.) 當 the_string 離開有效範圍 ( 即函式結束 ), StringVar 的解構子會被呼叫, 將 the_string.value 回收至自由儲存區 (the freestore ) greeting.value 仍然還在,可以被存取、被回收

56 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 56 When To Include a Copy Constructor 當一個類別的定義 ( 即實做 ) 需用到指標及 new 來 動態配置記憶體, 就需要複製建構子 當一個類別的定義沒有用到指標及 new 來動態配 置記憶體, 就不需要複製建構子

57 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 57 The Big Three 大三元包括 複製建構子 指定運算元 ( 下頁說明 ) 解構子 如果需要定義其中一個, 三個就都需要定義

58 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 58 The Assignment Operator 給定以下宣告 : StringVar string(10), string2(20); 這個程式碼 string1 = string2; 是合法的語法 但是, 因為 StringVar‘s 的成員變數 value 是一個指 標, 我們會將 string1.value 及 string2.value 指向同一記憶體位置 會使得前面討論複製建構子所提的問題又再重現

59 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 59 Overloading = 解決之道就是覆蓋 ( overload ) 指定運算子 ( = ) ,讓 StringVar 的指定不致產生問題 = 運算子是以成員函式 (member function) 來定義 Example: operator = declaration void operator=(const StringVar& right_side); right_side 是 = 運算子右邊的引數

60 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 60 Definition of = StringVar 的 = 運算子的實做之一 : void StringVar::operator= (const StringVar& right_side) { int new_length = strlen(right_side.value); if (( new_length) > max_length) new_length = max_length; for(int i = 0; i < new_length; i++) value[i] = right_side.value[i]; value[new_length] = '\0'; }

61 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 61 = Details 這個 StringVar = 的版本的作法是 比較 = 左右兩個 StringVar 物件的長度 最多只改變左邊 StringVar 物件可允許的最大長度 會將右邊物件的字串內容複製到左邊物件,而且彼此獨 立不會互相影響

62 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 62 Problems with = 這個 = 的實做的問題 通常我們不會去管右邊物件的字串內容大小,我們希望 要一個右邊物件的完整複製品 要完成以上要求, 我們需要先回收左邊物件的動態陣列, 然後配置夠大的動態陣列來容納右邊物件的字串內容 下頁顯示採用以上方法的一個嘗試,但這是一個有問題 (buggy) 的 = 運算子實做

63 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 63 Another Attempt at = void StringVar::operator= (const StringVar& right_side) { delete [ ] value; int new_length = strlen(right_side.value); max_length = new_length; value = new char[max_length + 1]; for(int i = 0; i < new_length; i++) value[i] = right_side.value[i]; value[new_length] = '\0'; }

64 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 64 A New Problem With = 上頁的 = 運算子實做的問題 如果有人無聊到將 = 的左右兩邊設為相同物件的話 my_string = my_string; 上頁的 = 運算子實做先回收左方物件的動態字元陣列. 由於左右兩邊為相同物件, 右方的動態字元陣列也被回 收了,沒有辦法執行 strlen(right_side.value) ,也無法 利用 right_side.value[i] 得到原來的各個字元

65 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 65 A Better = Operator void StringVar::operator = (const StringVar& right_side) { int new_length = strlen(right_side.value); if (new_length > max_length)// 只有需要更多空間 { // 時才回收 delete [ ] value; max_length = new_length; value = new char[max_length + 1]; } for (int I = 0; i< new_length; i++) value[i] = right_side.value[i]; value[new_length] = '\0'; }

66 Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 66 Section 12.3 Conclusion Can you Explain why an overloaded assignment operator is not needed when the only data consist of built-in types? Explain what a destructor does? Explain when a copy constructor is called?


Download ppt "Chapter 12 Pointers and Dynamic Arrays. Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 2 Overview Pointers (12.1) Dynamic Arrays."

Similar presentations


Ads by Google