iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 4
0
自我挑戰組

30 Days 如何把 C 語言偽裝成高階語言 OWO /系列 第 4

Days 4: 重溫指標:靜態變數的地址、函數回傳地址

▌來一個比較複雜一點點的例子:


現在我有一個函數,裏面有一個 靜態(static) 變數 a.

void function(){
    static int a;
}

靜態變數 意味著變數被宣告後,
即使變數所在的子程序結束,所擁有的地址及儲存空間均不會被剷除。

我現在想做 按址傳遞(call by address) 的相反動作,
平時 按址傳遞 是為了令 子程序/函數 可以改變 主程序 變數的值,
可以在函數中做到 交換(swap) 、排序(sort) ...... 等行為。


▌嗯。

現在我想把行為倒轉, (至於為什麼要這樣做?說到 垃圾回收 某篇再解釋。
主程序 可以改變 子程序/函數靜態變數的值。

(注意祇有 靜態變數 才可以,
因為正常方式宣告的變數,所擁有的空間會在子程序返回時被消滅)


▌所以要怎麼做呢?

先做個比較簡單有回傳的:

int *function(){
    static int a;
    return &a;
}
int main(){
    int *get_a = function();
    *get_a = 1;
    return 0;
}

上面的程序改變了 a 的數值。

▌做了什麼?:

函數 function() 回傳了 a 的地址,地址的類型為 int*
(即所謂的回傳指標 (指標這個字眼真的很抽象
同樣類型為 int*get_a 接收了 a 的地址,
然後基於這個地址的取值,改變了 a 的數值(儲存空間)。

每一格空間都有唯一的地址,只要依據某一個地址,就可以鎖定某一格空間。

可以回去看 Day 3 的圖,原理完全一樣,只不過 a 換成 get_ab 換成 a


......

▌在某些情況下,我們不希望地址以回傳方式接收:

  1. 可能是 無法確保地址一定被接收了。
    因為可以空運行有回傳的函數。 eg. function(); (前面沒有等號
    可以引發嚴重的問題,例如之後會提到的 malloc(),會導致內存洩漏
    .

  2. 可能是 嚴格的代碼編寫風格/規範
    就像接口/介面的約定保證了輸入輸出
    .

  3. 可能是 想回傳值只用作錯誤碼檢測
    方便調試 和 例外處理,
    例如 fopen_s() 的情況。


下一篇介紹 不使用回傳地址方式 的複雜例子。


上一篇
Days 3: 重溫指標:記憶體地址 、 儲存空間
下一篇
Days 5: 重溫指標:不使用回傳地址方式的函數
系列文
30 Days 如何把 C 語言偽裝成高階語言 OWO /31

尚未有邦友留言

立即登入留言