“當陣列名作為引數被傳遞時,若形引數組中各元素髮生了變化,則原實引數組各元素的值也隨之變化。”
像這樣的說法,或者說規則、現象,是沒有錯的,但是去記這種規則,是很難真正學會、理解現象的本質的。
在C語言中,呼叫函式時,總是把實參的值複製給形參(形參是另一個變數)。
假設一個函式宣告如下:
其呼叫形式如下:
那麼 argument 就是實參,param 就是形參,兩者位於不同的記憶體地址。
呼叫 func 時,會將 argument 的值賦給 param ,然後執行 func ,func 內部無論怎麼修改 param 都不會影響到 argument 變數,與param/argument的型別無關。
因為 param 實際上是這一次呼叫 func 所建立的棧幀裡的變數(有關棧幀,堆疊等概念,只能請你自行了解了,下圖為 UNIX/Linux 中程序的記憶體儲存形式,其中的 stack 就是用於函式執行使用的,每次函式呼叫都會形成一個棧幀:frame,函式結束時棧幀釋放)。
那麼為什麼“傳遞陣列(名)”時實參和形參好像是“同一個東西”了呢?
因為當你“傳遞陣列(名)”的時候,實質上是在傳遞地址
因為 argument 和 param 都是指向陣列所在記憶體的首地址(起始地址),所以修改 param[i] 起到的效果和修改 argument[i] 是一樣的。
注意,我們依然滿足“修改 param,不會影響到 argument ”,現在的情況是修改 param[i] 相當於修改argument[i]。因為 param[i] 其實就是 *(param+i),argument[i] 就是 *(argument+i),而 param 和 argument 儲存(指向)著同一個地址。
並且根據前面說到的兩個完全等價的函式宣告,你應該可以看出,argument 是一個不可被修改的陣列名,但 param 實際上是一個指標變數,是可以被修改的,比如說在 func 內部執行以下語句:
之後局面就變成了:
此時修改 param[i] 就與 argument[i] 毫無關係了,並且修改 param 也沒有影響到 argument。
以上內容其實認真、細心地去看一些好的書籍是能夠學到的,所以我一直說學C就去看一些經典的書。影片和差書我也看過一些,都不行,都是希望“速成”,只管記住規則而不去真正的理解,這樣我覺得是有害的。
“當陣列名作為引數被傳遞時,若形引數組中各元素髮生了變化,則原實引數組各元素的值也隨之變化。”
像這樣的說法,或者說規則、現象,是沒有錯的,但是去記這種規則,是很難真正學會、理解現象的本質的。
在C語言中,呼叫函式時,總是把實參的值複製給形參(形參是另一個變數)。
假設一個函式宣告如下:
其呼叫形式如下:
那麼 argument 就是實參,param 就是形參,兩者位於不同的記憶體地址。
呼叫 func 時,會將 argument 的值賦給 param ,然後執行 func ,func 內部無論怎麼修改 param 都不會影響到 argument 變數,與param/argument的型別無關。
因為 param 實際上是這一次呼叫 func 所建立的棧幀裡的變數(有關棧幀,堆疊等概念,只能請你自行了解了,下圖為 UNIX/Linux 中程序的記憶體儲存形式,其中的 stack 就是用於函式執行使用的,每次函式呼叫都會形成一個棧幀:frame,函式結束時棧幀釋放)。
那麼為什麼“傳遞陣列(名)”時實參和形參好像是“同一個東西”了呢?
因為當你“傳遞陣列(名)”的時候,實質上是在傳遞地址
因為 argument 和 param 都是指向陣列所在記憶體的首地址(起始地址),所以修改 param[i] 起到的效果和修改 argument[i] 是一樣的。
注意,我們依然滿足“修改 param,不會影響到 argument ”,現在的情況是修改 param[i] 相當於修改argument[i]。因為 param[i] 其實就是 *(param+i),argument[i] 就是 *(argument+i),而 param 和 argument 儲存(指向)著同一個地址。
並且根據前面說到的兩個完全等價的函式宣告,你應該可以看出,argument 是一個不可被修改的陣列名,但 param 實際上是一個指標變數,是可以被修改的,比如說在 func 內部執行以下語句:
之後局面就變成了:
此時修改 param[i] 就與 argument[i] 毫無關係了,並且修改 param 也沒有影響到 argument。
以上內容其實認真、細心地去看一些好的書籍是能夠學到的,所以我一直說學C就去看一些經典的書。影片和差書我也看過一些,都不行,都是希望“速成”,只管記住規則而不去真正的理解,這樣我覺得是有害的。