2024年1月30日 星期二

C語言使用物件導向(面向對象) - 指標

在談物件導向第三個特性前,我們先聊聊什麼是指標?指標直白的說,他就是一個位址,指向變數的記憶體位址。通常書上都是這樣說的,但就是因為說的太簡單,常常讓初學者摸不著頭緒,這時候就要了解一般變數與指標變數的差別。

當開發者定義了一個變數,編譯器就會在記憶體劃一塊開發者指定變數型別的大小,比如double a; 就會劃一塊8-byte的空間給a,位址是編譯器決定,開發者不會知道這位址,若要知道,可以用&a來得知。而若開發者定義了一個指標變數,編譯器是"不會"依開發者指定變數型別,劃一塊記憶體,一律是劃一塊"指標"型別的記憶體,也是就說無論是double* a; 還是 int* b;都是劃一塊4-byte的空間,前面的型別是指,這個指標是指向什麼樣型別的變數。(32位元系統中,一個指標佔用4-byte(32位元)的記憶體空間)

若是一般變數,只定義沒有指定初始值,裡面的值可能是0或是未知數;定義指標變數沒有指定初始值,一樣可能是0或是未知數,不管是哪個數字都非常危險,所以若定義一個指標變數沒有指定初始值,直接拿來做使用是非常危險的。指定初始值是什麼意思?就是他一定要指到一個,之前開發者定義的一個變數位址,若不做這件事就開始操作,保證會出問題。也就是說,一般定義一個變數,他是已經實體化了,編譯器會幫我們開一個空間放值;而定義一個指標,他並沒有實體化,必須指到一個已實體化的位址。

拿比喻來說,我們人是有軀殼以及靈魂的,定義一個普通的變數,就是實體化,就是代表是一個完整的生命個體,若是只有定義指標,是只有軀殼的,必須把靈魂放到軀殼裡,這邊的靈魂就是劃定的記憶體空間並已存放值,這生命個體才會動作。這也表示,這個軀殼裡面可以抽換不同的靈魂,另外,就算是不同的軀殼,放入同一個靈魂,不同的軀殼都可以連接到同一個靈魂,可以用不同的軀殼同步控制同一個靈魂,就像是被人家拿指甲毛髮被做草人替身一樣,雖然是不同的軀殼,但可以連接到草人替身控制的本人一樣。指標就是那個還未被施法的草人,指標指定值後,就是草人替身被施巫術了。

我們先把指標放在一邊,來討論其他實體化的變數,實體化的意思是已經在記憶體上劃了一塊空間,除了單純的變數,還會有array, struct, function…等, 一般的變數取址用&,而array, struct,以及function,都是使用他的名稱,即為位址。要知道這塊已在記憶體劃出的一塊空間狀況,除了位址,另一個重要的資訊為其空間的大小,我們才知道從哪開始,空間佔了多少。array可以藉由資料型別,以及一開始定義的陣列大小作計算得到。struct可以藉由struct的定義來計算struct的大小。function則不需要知道其大小,因為執行函式前會先把program counter存起來,執行完函式會return回去。但若要把函式的操作,當作一般變數賦值來賦值去,一定要認識函式指標。

函式指標讓人覺得比較困難,是因為他的使用及定義都與一般變數不太一樣,如果不用typedef來定義函式指標,就要寫的很長,而且初學者腦袋會有點轉不過來,因為一般的變數是型別定義在前,變數名在後,函數指標變數定義不照這個規則,下面的形式,fun_t就是定義的函式指標變數

void (*fun_t)(void);

以下是利用typedef定義function的格式(參數格式、返回值格式),fun_t是指一種函式指標的型別

typedef void (*fun_t)(void);

利用typedef定義struct的格式

typedef struct _DigitalNumberConfig {
    bool alignRightDigits;
    uint8_t fixedNumberDigits;
    uint8_t numberOfDigits;
    uint32_t maximumValue;
} DigitalNumberConfig_t;

所以若要定義一個指向struct的指標,及定義一個指向function的指標如下,operation是函式指標變數

DigitalNumberConfig_t* dnConfig;
fun_t operation; 

我們回到草人替身的話題上,若定義一個函式指標,它充其量就是一個草人而已,需要施巫術,也就是給他一個靈魂,給他一個之前就實體化,格式一模一樣的函式位址,這個草人替身才會有作用。函式指標是這麼想的,所以struct pointer,以及一般的pointer都可以這樣想像。世界社會資源有限,記憶體也有限,若已經在記憶體中定義及佔用空間,若需要一模一樣的資訊空間,不妨用指標代替。

把程式設計師比喻為巫師,可以製作草人並讓他連接到真人成為草人替身,而真人是需要透過母親懷孕10個月生產下來,再透過戶政單位登記有這個真人,就像是我們在程式中直接定義變數或是實體化結構(類似物件),還要經過編譯(懷孕生產)後,才會在記憶體登記有這個變數。草人製作出來後,是沒有作用的,可利用兩種方式讓他作用,一是連接到真人,使草人變成替身,控制連結到真人。另一個是"魅烙可 "巫術,駭進戶政單位開一個指定大小位子,將草人連接到那,但這巫術畢竟不是正常管道,使用完畢需要釋放掉這個位子,否則會有問題發生,但這個好處是不用再經過懷孕生產登記這一套複雜的流程,可以說開就開,說關就關,一切由巫師自己控制。

以上的"魅烙可 "巫術即為malloc;另外*這個符號是不是像草呢?

0 意見:

張貼留言