go語言關於切片型別記憶體位址的理解

2021-09-24 11:32:11 字數 2146 閱讀 4308

學習go語言切片型別時遇到了這樣乙個問題。

首先,在go中,切片型別的變數實際上存放的是乙個位址,該位址即為其引用的底層陣列的第乙個元素的位址,也可以說是這個陣列的位址。

如圖所示,建立乙個名為s的切片:

var s =

int

變數s儲存在棧區,其位址為0x000050420,而其值並不是陣列[1, 2, 3],而是存放的陣列[1, 2, 3]的位址。該陣列存放在堆區,位址為0x000074080(第乙個元素的位址,後面開闢了連續的位址空間存放後續元素)。

因此,不難想到,將切片傳入函式中,形參是實參值的拷貝,此時雖然形參和實參本身是不同的記憶體空間,但他們的值使得各自都指向同一底層陣列,因此當形參改變時(新增元素,改變某元素值),函式呼叫後實參同樣會被改變(其實是指向的底層陣列的改變),這和其他一些型別傳入函式時有很大不同

package main

import

("fmt"

)func

change

(a [

]int

)func

main()

/*結果

[0 0 0 0 0]

0xc0000700c0

[2 0 0 0 0]

[2 0 0 0 0]

0xc0000700c0

/*

不難發現,形參a和實參s都指向了相同的陣列位址,通過形參a改變陣列元素值,實參同樣會受到影響。那我們新增乙個元素試試。

package main

import

("fmt"

)func

change

(a [

]int

)func

main()

/*結果

[0 0 0 0 0]

0xc000060050

[0 0 0 0 0 1]

[0 0 0 0 0]

0xc0000700c0

/*

這時發現實參指向的陣列竟然沒有變化,怎麼回事?

看輸出結果明白了,形參新增元素後指向的位址變了,因此其指向的陣列是原陣列的拷貝,當然不會影響原陣列了。

什麼原因呢?當新增元素時,若陣列容量不夠的話,則將原陣列進行擴容,擴容後由於要求陣列的位址空間連續,因此原位址不滿足條件,會在開闢一片新的空記憶體區域存放擴容後的陣列,因此形參存放的位址改變了,而實參對應的原陣列並沒有改變。

package main

import

("fmt"

)func

change

(a [

]int

)func

main()

/*結果

[0 0 0 0 0]

0xc000074080

[0 0 0 0 0 1]

[0 0 0 0 0]

0xc000074080

/*

發現了和預計結果不一樣的現象。就如同**的一樣,形參和實參指向的位址是一樣的,但為什麼和實參的輸出不一樣?同一塊記憶體區域還能存兩個不同的陣列?

經過一番學習,也在網上提問尋求答案後明白了,實際上我的**並沒有問題,s的輸出應該和a是一樣的,只不過s初始化時預定義的長度為5,當陣列長度變為6之後s並不能檢視到陣列後面的元素,需要重新進行切片(實際上是把s的右指標向後移動,增加s的長度),這樣就能看到變化了

package main

import

("fmt"

)func

change

(a [

]int

)func

main()

/*結果

[0 0 0 0 0]

[0 0 0 0 0 0]

0xc000074080

[0 0 0 0 0 1]

[0 0 0 0 0 1]

0xc000074080

/*

和**的一樣,完美解決困惑。

go語言記憶體,位址,指標

指標就是位址 列印出變數的記憶體和位址 a可以取到a的位址 簡單說可以說位址就是索引,就是門牌號,記憶體就是倉庫,裡面存了東西,存了值 package main import fmt func main int儲存int的位址,int儲存int的位址 定義乙個變數p,型別為 int var p in...

C語言記憶體位址

任務清單 c語言在記憶體中一共分為5個區域 記憶體棧區 存放區域性變數名 由編譯器自動分配釋放,存放函式的引數值,區域性變數的值等,函式呼叫結束後釋放記憶體空間。通常是用於那些在編譯期間就能確定儲存大小的變數的儲存區,用於在函式作用域內建立,在離開作用域後自動銷毀的變數的儲存區。通常是區域性變數,函...

關於記憶體和記憶體位址的詳解

記憶體位址用4位16進製制和8位16進製表示的區別。例如經常可以看到某些書籍上寫的記憶體位址0x0001,在另外一些書籍上寫的記憶體位址又變成了0x00000001。都是表示的編號為1的記憶體位址,為什麼乙個是4位16進製表示,另外乙個又是用8位16進製表示呢?首先,必須要知道記憶體位址只是乙個編號...