中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go語言指針的詳細介紹

發布時間:2021-08-27 17:04:57 來源:億速云 閱讀:98 作者:chen 欄目:數據庫

本篇內容介紹了“Go語言指針的詳細介紹”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

Go語言為程序員提供了控制數據結構指針的能力,但是,并不能進行指針運算。Go語言允許你控制特定集合的數據結構、分配的數量以及內存訪問模式,這對于構建運行良好的系統是非常重要的。指針對于性能的影響不言而喻,如果你想要做系統編程、操作系統或者網絡應用,指針更是不可或缺的一部分。

指針(pointer)在Go語言中可以被拆分為兩個核心概念:類型指針,允許對這個指針類型的數據進行修改,傳遞數據可以直接使用指針,而無須拷貝數據,類型指針不能進行偏移和運算。 切片,由指向起始元素的原始指針、元素數量和容量組成。
受益于這樣的約束和拆分,Go語言的指針類型變量即擁有指針高效訪問的特點,又不會發生指針偏移,從而避免了非法修改關鍵性數據的問題。同時,垃圾回收也比較容易對不會發生偏移的指針進行檢索和回收。

切片比原始指針具備更強大的特性,而且更為安全。切片在發生越界時,運行時會報出宕機,并打出堆棧,而原始指針只會崩潰。

C/C++中的指針

說到 C/C++ 中的指針,會讓許多人“談虎色變”,尤其是對指針的偏移、運算和轉換。

其實,指針是 C/C++ 語言擁有極高性能的根本所在,在操作大塊數據和做偏移時即方便又便捷。因此,操作系統依然使用C語言及指針的特性進行編寫。

C/C++ 中指針飽受詬病的根本原因是指針的運算和內存釋放,C/C++ 語言中的裸指針可以自由偏移,甚至可以在某些情況下偏移進入操作系統的核心區域,我們的計算機操作系統經常需要更新、修復漏洞的本質,就是為解決指針越界訪問所導致的“緩沖區溢出”的問題。

要明白指針,需要知道幾個概念:指針地址、指針類型和指針取值,下面將展開詳細說明。

認識指針地址和指針類型

一個指針變量可以指向任何一個值的內存地址,它所指向的值的內存地址在 32 和 64 位機器上分別占用 4 或 8 個字節,占用字節的大小與所指向的值的大小無關。當一個指針被定義后沒有分配到任何變量時,它的默認值為 nil。指針變量通常縮寫為 ptr。

每個變量在運行時都擁有一個地址,這個地址代表變量在內存中的位置。Go語言中使用在變量名前面添加&操作符(前綴)來獲取變量的內存地址(取地址操作),格式如下:

ptr := &v  // v 的類型為 T

其中 v 代表被取地址的變量,變量 v 的地址使用變量ptr 進行接收,ptr 的類型為*T,稱做 T 的指針類型,*代表指針。

指針實際用法,可以通過下面的例子了解:

package mainimport ("fmt")func main() {var cat int = 1var str string = "banana"fmt.Printf("%p %p", &cat, &str)}

運行結果:

0xc042052088 0xc0420461b0

代碼說明如下:第 8 行,聲明整型變量cat。 第 9 行,聲明字符串變量str。 第 10 行,使用 fmt.Printf 的動詞%p打印 cat 和 str 變量的內存地址,指針的值是帶有0x十六進制前綴的一組數據。
提示:變量、指針和地址三者的關系是,每個變量都擁有地址,指針的值就是地址。

從指針獲取指針指向的值

當使用&操作符對普通變量進行取地址操作并得到變量的指針后,可以對指針使用*操作符,也就是指針取值,代碼如下。

package mainimport ("fmt")func main() {// 準備一個字符串類型var house = "Malibu Point 10880, 90265"// 對字符串取地址, ptr類型為*stringptr := &house// 打印ptr的類型fmt.Printf("ptr type: %T\n", ptr)// 打印ptr的指針地址fmt.Printf("address: %p\n", ptr)// 對指針進行取值操作value := *ptr// 取值后的類型fmt.Printf("value type: %T\n", value)// 指針取值后就是指向變量的值fmt.Printf("value: %s\n", value)}

運行結果:

ptr type: *string
address: 0xc0420401b0
value type: string
value: Malibu Point 10880, 90265

代碼說明如下:第 10 行,準備一個字符串并賦值。 第 13 行,對字符串取地址,將指針保存到變量 ptr 中。 第 16 行,打印變量ptr 的類型,其類型為 *string。 第 19 行,打印 ptr 的指針地址,地址每次運行都會發生變化。 第 22 行,對 ptr 指針變量進行取值操作,變量 value 的類型為 string。 第 25 行,打印取值后 value 的類型。 第 28 行,打印 value 的值。
取地址操作符&和取值操作符*是一對互補操作符,&取出地址,*根據地址取出地址指向的值。

變量、指針地址、指針變量、取地址、取值的相互關系和特性如下:對變量進行取地址操作使用&操作符,可以獲得這個變量的指針變量。 指針變量的值是指針地址。 對指針變量進行取值操作使用*操作符,可以獲得指針變量指向的原變量的值。

使用指針修改值

通過指針不僅可以取值,也可以修改值。

前面已經演示了使用多重賦值的方法進行數值交換,使用指針同樣可以進行數值交換,代碼如下:

package mainimport "fmt"// 交換函數func swap(a, b *int) {// 取a指針的值, 賦給臨時變量tt := *a// 取b指針的值, 賦給a指針指向的變量*a = *b// 將a指針的值賦給b指針指向的變量*b = t}func main() {// 準備兩個變量, 賦值1和2x, y := 1, 2// 交換變量值swap(&x, &y)// 輸出變量值fmt.Println(x, y)}

運行結果:

2 1

代碼說明如下:第 6 行,定義一個交換函數,參數為 a、b,類型都為 *int 指針類型。 第 9 行,取指針a 的值,并把值賦給變量t,t 此時是 int 類型。 第 12 行,取 b 的指針值,賦給指針a 指向的變量。注意,此時*a的意思不是取 a 指針的值,而是“a 指向的變量”。 第 15 行,將 t 的值賦給指針b 指向的變量。 第 21 行,準備 x、y 兩個變量,分別賦值為 1 和 2,類型為 int。 第 24 行,取出 x 和 y 的地址作為參數傳給 swap() 函數進行調用。 第 27 行,交換完畢時,輸出 x 和 y 的值。
*操作符作為右值時,意義是取指針的值,作為左值時,也就是放在賦值操作符的左邊時,表示 a 指針指向的變量。其實歸納起來,*操作符的根本意義就是操作指針指向的變量。當操作在右值時,就是取指向變量的值,當操作在左值時,就是將值設置給指向的變量。

如果在 swap() 函數中交換操作的是指針值,會發生什么情況?可以參考下面代碼:

package mainimport "fmt"func swap(a, b *int) {b, a = a, b}func main() {x, y := 1, 2swap(&x, &y)fmt.Println(x, y)}

運行結果:

1 2

結果表明,交換是不成功的。上面代碼中的 swap() 函數交換的是 a 和 b 的地址,在交換完畢后,a 和 b 的變量值確實被交換。但和 a、b 關聯的兩個變量并沒有實際關聯。這就像寫有兩座房子的卡片放在桌上一字攤開,交換兩座房子的卡片后并不會對兩座房子有任何影響。

示例:使用指針變量獲取命令行的輸入信息

Go語言內置的 flag 包實現了對命令行參數的解析,flag 包使得開發命令行工具更為簡單。

下面的代碼通過提前定義一些命令行指令和對應的變量,并在運行時輸入對應的參數,經過 flag 包的解析后即可獲取命令行的數據。

【示例】獲取命令行輸入:

package main// 導入系統包import ("flag""fmt")// 定義命令行參數var mode = flag.String("mode", "", "process mode")func main() {// 解析命令行參數flag.Parse()// 輸出命令行參數fmt.Println(*mode)}

將這段代碼命名為 main.go,然后使用如下命令行運行:

go run main.go --mode=fast

命令行輸出結果如下:

fast

代碼說明如下:第 10 行,通過 flag.String,定義一個 mode 變量,這個變量的類型是 *string。后面 3 個參數分別如下:參數名稱:在命令行輸入參數時,使用這個名稱。參數值的默認值:與 flag 所使用的函數創建變量類型對應,String 對應字符串、Int 對應整型、Bool 對應布爾型等。參數說明:使用 -help 時,會出現在說明中。第 15 行,解析命令行參數,并將結果寫入到變量 mode 中。第 18 行,打印 mode 指針所指向的變量。
由于之前已經使用 flag.String 注冊了一個名為 mode 的命令行參數,flag 底層知道怎么解析命令行,并且將值賦給 mode*string 指針,在 Parse 調用完畢后,無須從 flag 獲取值,而是通過自己注冊的這個mode 指針獲取到最終的值。代碼運行流程如下圖所示。

圖:命令行參數與變量的關系

創建指針的另一種方法——new() 函數

Go語言還提供了另外一種方法來創建指針變量,格式如下:

new(類型)

一般這樣寫

str := new(string)*str = "Go語言教程"fmt.Println(*str)

new() 函數可以創建一個對應類型的指針,創建過程會分配內存,被創建的指針指向默認值。

“Go語言指針的詳細介紹”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

海淀区| 丽江市| 榆林市| 印江| 阳高县| 无棣县| 乌拉特后旗| 新兴县| 南阳市| 长治市| 巴塘县| 德兴市| 郎溪县| 定兴县| 乌鲁木齐县| 万年县| 印江| 六安市| 元谋县| 吉木萨尔县| 罗江县| 耿马| 石首市| 保康县| 菏泽市| 寿宁县| 龙门县| 南城县| 蓝山县| 鄂托克前旗| 华容县| 金山区| 尚志市| 车险| 玉溪市| 页游| 安顺市| 屏南县| 裕民县| 县级市| 镇平县|