1 / 89

EL 1012 程式設計

EL 1012 程式設計. Program Design. Instructor : Po-Yu Kuo 教師 : 郭柏佑. Ch. 12 指位器 (pointer). 本章簡介. 指位器 (pointer) 也是一種變數 , 但是此種變數儲存的並非一般數值 , 而是記憶體位址。 當指位器變數所存的值是位址時 , 我們稱此指位器指向該位址所表示的記憶體空間。 指位器可以用來表示複雜的資料的結構 , 或者有效率的存取陣列的資料。. 記憶體位址. 記憶體位址.

alagan
Download Presentation

EL 1012 程式設計

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. EL 1012程式設計 Program Design Instructor:Po-Yu Kuo 教師:郭柏佑 Ch. 12 指位器 (pointer)

  2. 本章簡介 • 指位器 (pointer) 也是一種變數, 但是此種變數儲存的並非一般數值, 而是記憶體位址。 • 當指位器變數所存的值是位址時, 我們稱此指位器指向該位址所表示的記憶體空間。 • 指位器可以用來表示複雜的資料的結構, 或者有效率的存取陣列的資料。

  3. 記憶體位址

  4. 記憶體位址 • 但是, 因為使用指位器的過程中, 會涉及許多記憶體位址與空間的概念, 造成不了解此種概念的讀者學習上的困難。 • 指位器是專門用來存放記憶體位址的變數。 • 我們可以把記憶體的內部, 想像成一個一個排列整齊可用來裝填資料的小格子, 每個小格子的大小都相等 (1 byte)。

  5. 本章簡介 • 我們可以利用 & 算符, 找出變數在記憶體中被配置的位址, 語法如下: • 在任何變數名稱前加上 & 算符後, 就表示該變數在記憶體中的位址, 而不是變數值。 • 利用 printf ( ) 配合輸出格式 %p, 就可以輸出以 16 進位數值表示的記憶體位址, 如下:

  6. 記憶體位址

  7. 記憶體位址 • 因為 4 個變數都是整數型別, 所以在記憶體中各佔 4 bytes。 • 在記憶體中, 每個 byte 都有獨立的位址, 以代表該空間在記憶體中的位置。

  8. 記憶體位址 4 bytes

  9. 指位器的基本用法

  10. 指位器的基本用法 • 指位器的運用, 主要是在一種稱為『指向』的觀念。 • 當指位器中儲存著一個變數的位址時, 我們稱此指位器指向該變數。 • 宣告的語法如下:

  11. 指位器的基本用法 • 資料型別:指位器的型別, 必須與該指位器所指向的變數型別相同。 • *:稱為『間接』算符 (indirection), 意指指示器存放的是儲存變數的位址, 不能直接取得變數的值, 必須在指位器上使用間接算符才能取得變數值。 • 宣告指位器變數時, 需在變數名稱前加上此算符。

  12. 指位器的基本用法 • 指位器:也就是指位器變數的名稱, 命名的原則和一般變數相同。 • 例如:

  13. 指位器的基本用法 • 如此一來, ptr 便是指向 number 的指位器了。

  14. 指位器的空間大小 • 由於指位器記錄的是記憶體位址, 所以不管指位器宣告成何種型別, 在記憶體中都會配置相同的空間 (4 bytes), 我們可以利用 sizeof ( ) 來驗證, 如下:

  15. 指位器的空間大小

  16. 指位器的空間大小

  17. 設定指位器的值 • 指位器也是一個變數, 所以和變數一樣可以設定其值。 • 如果我們將指位器採用與變數相同的設定方式, 如下:

  18. 設定指位器的值 • 由於 ptr 本身未被設定初始值, 所以其值有可能是任何數值, 換言之, ptr 可能指向任何的記憶體空間。 • 例如其它程式、甚至作業系統正在使用的記憶體空間。此時若將數值 35 指定到此不知位於何處的記憶體空間, 有可能導致程式執行發生錯誤。 • 所以, 指位器不能使用上述的方法來設定其值。

  19. 設定指位器的值 • 當我們要將數值指定給指位器時, 我們需要以下面的步驟來完成: • 1.事先宣告一個同型別的變數, 再讓指位器指向此變數位址: • 2.完成上述指定動作之後, 就可以利用 * 算符, 從指位器中取出數值。也就是說 *ptr 的值會等於 10。

  20. 設定指位器的值 • 上面步驟完成後, 指位器與變數間的關係如下圖: • 我們先宣告 3 種不同型別的指位器, 讓其分別指向 3 個變數, 然後輸出其值。如下:

  21. 設定指位器的值 將指位器指向變數

  22. 設定指位器的值

  23. 指位器的轉型 • 指位器只能指向同型別的變數位址, 絕對不能有以下的情形: • 若想將指位器指向不特定型別的變數, 可使用 void 這個特殊的型別來宣告指位器變數。 • void 型別的指位器可指向任何型別。

  24. 指位器的轉型 • 但要取用指位器所指的變數值時, 必須做強制型別轉換才能取出正確的值:

  25. 指位器的運算 • 因為指位器內儲存的是位址, 所以對指位器做加減, 就等於是將所存的位址做加減, 所得到的將會是鄰近的位址。

  26. 指位器的運算

  27. 指位器的運算

  28. 指位器的運算 • 對 ptri 而言, 加減 1 時, 位址值是加減 4 (bytes); 但對 ptrc 加減 1 時, 位址值則只加減 1 (bytes)。 • 這是因為對指位器做加減時, 是以指位器型別所佔的 byte 數為單位進行加減, 所以 int 型別一次就是加減 4、char 型別一次是加減 1。 • 同理 float、double 型別的指位器加減時, 位址值分別是加減 4、8 (bytes)。

  29. 指位器的運算 • 要取得指位器鄰近位址內的值, 可直接在前面加上 * 算符, 如下:

  30. 指位器的運算 • 由於 * 算符的優先權高於算術算符, 所以我們要在 ptri+1 外面加上括號, 否則會變成 *ptri 的值再加上 1。 • 注意, 由於指位器的值是變數的位址, 所以任意兩個指位器相加減, 等於是兩個記憶體位址相加減, 其結果是沒有意義的。

  31. 使用指位器的好處 • 變數可以直接儲存數值, 所以需要數值時可以直接讀取變數值。 • 而指位器儲存的卻是存放變數值的記憶體位址, 所以如果要讀取數值時, 必須透過指位器內儲存的位址去尋找記憶體中位址的空間, 才能讀到數值。 • 但是,指位器的用途並非只是單純的存取數值, 指位器的主要用途如下:

  32. 使用指位器的好處 • 指位器在某些方面可以代替陣列的使用。 • 陣列是在記憶體中一段被編譯器配置的連續空間, 也就是說這些空間的位址是連續的。 • 如果採用指位器儲存位址的觀念來看, 我們把指位器作加減的運算, 也是可以讀取到儲存在連續記憶體空間內的資料。

  33. 使用指位器的好處 • 指位器適用函式間的傳址運算。 • 當函式間需要傳遞數值時, 如果使用指位器, 傳遞到函式中的引數不再只是將數值複製到函式中做處理, 而是將數值儲存的位址傳到函式, 由函式直接存取。 • 此時, 就算函式無傳回值, 引數的變數值也會經過函式的運算而有所改變, 這種做法可以改善函式只能有一個傳回值的缺點。

  34. 使用指位器的好處 • 有些特殊的資料結構 (Data Structure) 及相關演算法 (Algorithm), 都需利用指位器才能順利實作。

  35. 動態記憶體配置 (Dynamic Memory Allocation)

  36. 動態記憶體配置 • 甚麼是動態記憶體配置? • 當我們在程式開始宣告一個變數時, 編譯器就會所需的記憶體空間來存放這個變數的值。 • 只要在程式執行期間, 該變數會佔用一塊固定大小的記憶體空間, 就算程式想臨時擴大或縮小佔用的的空間也不行, 所以稱之為靜態記憶體配置。

  37. 動態記憶體配置 • 動態記憶體配置則是:當程式執行到一半, 發現它需要一塊記憶體空間來存放資料, 才向系統索取一塊沒有被其他程式使用的記憶體空間。 • 當此記憶體空間用不到時, 也可隨時將之釋放供其它程式使用, 如此可大幅的提高記憶體的使用效率。

  38. 動態記憶體配置 的語法 • 向系統索取記憶體區塊主要是透過 malloc ( ) 函式來做, 此函式的原型宣告放在stdlib.h, 使用時要將此含括檔含括進來。呼叫的語法如下: • 資料型別:新配置空間的型別。 • 個數:新配置多少同型別的變數空間。

  39. 動態記憶體配置 的語法 • 如果記憶體空間不夠分配時, 此函式會傳回 NULL 。 • 記憶體配置成功後, 則會傳回所配置記憶體空間的起始位址, 所以我們要先宣告一個指位器來接受傳回的位址。如下:

  40. 動態記憶體配置 的語法 • 上面的範例, 是初始化動態記憶體配置的寫法, 也就是在宣告指位器的同時, 便配置記憶體空間。 • 配置成功後, 使用 num 和 code 時, 就和使用以 int num [10]; 與 char code [5]; 取得的陣列記憶體空間一樣, 可任意儲存資料於其中。 • 空間使用完畢, 可用 free ( ) 函式將配置的記憶體釋放。

  41. 動態記憶體配置的特色:有需要, 才配置 • 動態記憶體配置的主要特色, 是我們不必在程式開始就先配置記憶體空間。 • 而是可在程式流程執行到一半, 發現有需要時, 才配置所需的空間。例如:

  42. 動態記憶體配置的特色:有需要, 才配置 • 不管是哪種配置方式, 記憶體空間使用完畢後, 一定要以 free ( ) 的語法將配置的記憶體空間釋放, 這是一個很重要的習慣, 可以讓記憶體的使用更具效率。 • 由於寫程式時無法預知使用者想計算多少個數字。 • 因此可設計成在使用者輸入數字個數後, 再動態配置所需的記憶體空間來存放數值。程式如下:

  43. 動態記憶體配置的特色:有需要, 才配置 使用者輸入數字個數 n 動態配置 n 個記憶體空間

  44. 動態記憶體配置的特色:有需要, 才配置

  45. 動態記憶體配置的特色:有需要, 才配置

  46. 指位器與陣列

  47. 指位器與陣列 • 指位器儲存的是記憶體的位址, 而陣列是記憶體中一段位址連續的記憶體空間。 • 用指位器代替陣列 • 使用動態配置的空間來儲存資料 • 使用指位器來儲存字串 • 指位器陣列 • 自行調整字串長度 • 利用指位器陣列作字串排序

  48. 用指位器代替陣列 • 雖然指位器是用來儲存位址的變數, 但我們可以採用動態記憶體配置的方法, 配置一塊記憶體空間給指位器。 • 因為我們可以設定配置多少空間, 就如同宣告陣列時, 設定陣列容量一樣。 • 使用動態記憶體配置配置一塊空間, 並讓指位器 ptr 指向此空間時。

  49. 用指位器代替陣列 • 若把這個空間看成是個陣列, 則 ptr+i 就相當於陣列中, 第 i 個陣列元素的位址。 • 並且可以利用 *(ptr+i) 的方式, 取得取得第 i 個陣列元素的數值。 • 如以下範例中, 我們將利用指位器代替陣列, 儲存 5 個由鍵盤輸入的數值, 並找出最大值:

  50. 使用動態配置的空間來儲存資料 動配置 5 個記憶體空間的位址 利用 *(ptr+i) 的方式, 取得第 i 個陣列元素的數值

More Related