Golang中陣列指標和指標陣列區別
區別二者,字面上只看後兩個字即可:
陣列指標 :它是一個指標,但是資料型別為陣列,或者說指向陣列
指標陣列 :它是一個陣列,該陣列的元素都為地址值
1.語法
var 變數名 *[陣列大小] 陣列型別:
var arrPtr *[size] Type
因為陣列指標是一個指標,所以在定義時,先寫 *, 表示定義一個指標,後面接資料型別
2.例項
一步一步建立,容易理解。
建立一個陣列指標,並賦值:
var arrPtr * [4]int // 建立一個指標 arrPtr,指向一個陣列
var arr = [4]int{1,2,3,4} // 建立一個陣列並初始化
arrPtr = &arr // 將陣列 arr的地址賦值給arrPtr
fmt.Println("將 arr 的記憶體地址賦值給陣列指標 arrPtr, arrPtr=",ptr)
輸出為:
將 arr 的記憶體地址賦值給陣列指標 arrPtr, arrPtr= &[1 2 3 4]
注意,輸出的結果不是地址(不是16進位制的數),在Golang中,直接輸出的是
&[元素1 元素2 ……]
我們可以輸出一下二者的地址:
fmt.Printf("arr 陣列的地址為:%p\n", &arr)
fmt.Printf("arrPtr 儲存的地址為:%p\n", arrPtr)
輸出為:
arr 陣列的地址為:0xc00000c3c0
arrPtr 儲存的地址為:0xc00000c3c0
可以看到,它倆的輸出時一樣的,因為將陣列 arr的地址賦值給了arrPtr,而arrPtr是一個指標,儲存的是記憶體地址。
當然arrPtr也有自己的記憶體地址,我們可以看一下:
fmt.Printf("arrPtr 指標自己的地址為:%p\n", &arrPtr)
輸出為:
arrPtr 指標自己的地址為:0xc000006028
3.通過指標訪問陣列
訪問陣列的元素可以通過下標來訪問,比如:arr[0] 即可訪問陣列arr的第一個元素。
但是我們學習了指標陣列,所以嘗試使用指標陣列來訪問元素內容,在Golang中,取地址的操作為 * (定址運算子) 。
因此,我們先取儲存的地址*arrPtr
,訪問到陣列 ,然後再下標取值*arrPt[0]
,程式碼如下:
*arrPtr[0]
實際上,這段程式碼編譯就會報錯,因為在Golang 中 * 定址運算子和 [] 中括號運算子的優先順序是不同的!
[] 中括號是初等運算子
- 定址運算子是單目運算子
初等運算子的優先順序是大於單目運算子的,因此先參與計算的是
arrPtr[0]
,arrPtr[0]
其實就是陣列的第一個元素,就是數字1。
數字1必然是int型別,而不是一個地址,因此針對數字1使用*定址運算子自然也就發生了錯誤。
解決問題的辦法很簡單,就是新增一個小括號,更改運算優先順序即可:
(*arrPtr)[0]
不過因為 * 在Golang中,建立了 arrPtr := &arr
這種類似地址關係後,* 允許不寫。
所以,訪問時候可以直接寫成arrPtr[0]
。事實上在工作開發過程中,這種寫法反而更加常見。實戰程式碼:
fmt.Println("(*arrPtr)[0] 通過指標訪問陣列的第一個元素:", (*arrPtr)[0])
fmt.Println("arrPtr[0] 通過指標訪問陣列的第一個元素:", arrPtr[0])
輸出:
(*arrPtr)[0] 通過指標訪問陣列的第一個元素: 1
arrPtr[0] 通過指標訪問陣列的第一個元素: 1
注意:僅對訪問下標時,定址運算子允許不寫!
它是一個陣列,該陣列的元素都為地址值
1.語法
var 變數名 [陣列大小] * 陣列型別:
var ptrArr [size] *Type
因為指標陣列是一個陣列,所以在定義時,先寫 [size], 表示定義一個陣列,後面再接指標 * 和 陣列的資料型別
2.例項
1.建立一個陣列指標, 陣列的型別為int,大小為4,並賦值:
var ptrArr [4]*int
a, b, c, d := 1, 2, 3, 4
arr2 := [4]int{a, b, c, d} // 拷貝四個變數的值為函式組元素
fmt.Println("陣列 arr2 :", arr2)
ptrArr = [4]*int{&a, &b, &c, &d} // 存的都是記憶體地址
fmt.Println("指標陣列 ptrArr :", ptrArr)
輸出:
陣列 arr2 : [1 2 3 4]
指標陣列 ptrArr : [0xc0000140f0 0xc0000140f8 0xc000014100 0xc000014108]
2.運算元據,檢視變化
(1).arr2的第一個元素改變, a 會不會變化,ptrArr 會不會變化?
arr2[0] = 100
fmt.Println("arr2 的值為:", arr2)
fmt.Println("a 的值為;", a)
fmt.Println("ptrArr 的值為;", *ptrArr[0])
輸出:
arr2 的值為: [100 2 3 4]
a 的值為; 1
ptrArr 的值為; 1
先看a 的值為 1解釋:
在Golang中,int,float,bool,string,array,struct都屬於值型別,資料拷貝時都是值拷貝,拷貝副本過來。
因此,儘管 arr2[0] = 100
執行了,只是修改了 arr2 的值,原來 a 的值不會受任何影響。因此,a 的值仍為1
ptrArr的值為1解釋:
ptrArr是指標陣列, 該陣列儲存都是 指標,也就是 a,b,c,d四個變數的記憶體地址。
其中,*ptrArr[0]
儲存的是 a 的記憶體地址;a 沒變, *ptrArr[0]
也不會變。所以輸出仍為1
我們可以檢視一下 ptrArr[0]
的值和 a 的地址是否一致:
fmt.Println("ptrArr[0] 的值:", ptrArr[0])
fmt.Printf("a 的記憶體地址為:%p\n", &a) // %p 佔位符表示地址值
輸出:
ptrArr[0] 的值: 0xc0000140f0
a 的記憶體地址為:0xc0000140f0
可以看到,它倆的值是一致的。
(2).指標陣列變化,a,b,c,d 會不會改變? 陣列 arr2 會不會改變?
*ptrArr[0] = 1000 // 指標陣列的第一個元素地址指向的值發生改變
fmt.Println("a 的值為:", a)
fmt.Println("arr2 的值為:", arr2)
輸出:
a 的值為: 1000
arr2 的值為: [100 2 3 4]
a 的值為: 1000 解析:
首先要明白一點:*ptrArr[0] = 1000
這段程式碼不會編譯報錯,因為ptrArr是指標陣列,按照運算子的執行順序,先 ptrArr[0]
獲取 a 的地址,然後再 *a
,這樣獲取的就是 a 的值
其實,解析的已經差不多了,ptrArr[0]
本來就是 a 的記憶體地址,所以*ptrArr[0] = 1000
執行後,就改變了 a 的值
arr2 的值為: [100 2 3 4] 解析:
arr2 拷貝了 a,b,c,d 值的副本,a的改變和 arr2 沒有關係的,各不會受影響。a 和 arr2 都是值型別,各自改變,互不影響
以上就是在學習Golang陣列指標和指標陣列時的一些筆記和感悟。
總結一下,陣列指標和指標陣列這兩個概念的區分,記住兩點即可:
- 後兩字是啥,則它就表示啥
- 定義時,最先寫的 程式碼 就已經表示了其是陣列還是指標
本作品採用《CC 協議》,轉載必須註明作者和本文連結