Golang 學習——陣列指標和指標陣列的區別

相守之路發表於2020-05-05

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 協議》,轉載必須註明作者和本文連結

相關文章