網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
前言
關(guān)于指針的主要幾點(diǎn):
- 指針類(lèi)型:一個(gè)指針類(lèi)型
*T
表示指向給定類(lèi)型的變量的所有指針的集合,該給定類(lèi)型T
稱(chēng)為基本類(lèi)型。未初始化的指針的值是nil
。 - 變量:一個(gè)變量是保存一個(gè)值的存儲(chǔ)位置。允許的值的集合由變量的類(lèi)型決定。
- 尋址操作:對(duì)于類(lèi)型為
T
的操作數(shù)x
,尋址操作&x
會(huì)產(chǎn)生一個(gè)指向x
的類(lèi)型為*T
的指針。對(duì)于指針類(lèi)型為*T
的操作數(shù)y
,指針間接尋址*y
表示y
指向的類(lèi)型為T
的變量。
本文使用的Go版本:
$ go version go version go1.18 darwin/amd64
練習(xí)1
var a int = 111 var b *int = &a fmt.Println("a的值是:", a) // 111 fmt.Println("a的地址是:", &a) // 0xc000016098 fmt.Println("b的值是:", b) // 0xc000016098 fmt.Println("b的地址是:", &b) // 0xc0000ac018 *b = *b + 1 fmt.Println(a, b) // 112 0xc000016098
代碼中聲明了一個(gè)整型的變量a
,以及一個(gè)指向整型變量a
的*int
類(lèi)型的指針變量b
。
內(nèi)存地址表示數(shù)據(jù)在內(nèi)存中存放的位置。如上圖所示,a
相當(dāng)于是內(nèi)存地址0xc000016098
的一個(gè)名字(用于引用計(jì)算機(jī)內(nèi)存地址),當(dāng)我們獲取a
的值時(shí),就是獲取內(nèi)存地址0xc000016098
存儲(chǔ)的數(shù)據(jù)。而指針類(lèi)型的變量b
(代表內(nèi)存地址0xc0000ac018
)存儲(chǔ)的是變量a
代表的地址,它存儲(chǔ)的值就是一個(gè)地址。
當(dāng)使用*b
進(jìn)行指針間接尋址時(shí),可以理解為:找到b
代表的內(nèi)存地址0xc0000ac018
中存儲(chǔ)的值,存儲(chǔ)的是一個(gè)地址0xc000016098
,于是去拿地址0xc000016098
中存儲(chǔ)的值111
。
當(dāng)對(duì)*b
進(jìn)行賦值時(shí)(首先賦值符號(hào)=
右側(cè)已經(jīng)計(jì)算出結(jié)果為112
了),將b
代表的內(nèi)存地址0xc0000ac018
中,存儲(chǔ)的地址0xc000016098
中,存儲(chǔ)的值改為112
。修改的是內(nèi)存地址0xc000016098
中存儲(chǔ)的值,所以再次打印a
(代表內(nèi)存地址0xc000016098
)的值時(shí),已經(jīng)變?yōu)榱?code>112。
練習(xí)2
對(duì)于類(lèi)型為T
的操作數(shù)x
,尋址操作&x
會(huì)產(chǎn)生一個(gè)指向x
的類(lèi)型為*T
的指針。
操作數(shù)必須是可尋址的,即變量、指針間接引用、切片索引操作;或者一個(gè)可尋址的結(jié)構(gòu)體操作數(shù)的字段選擇;或者一個(gè)可尋址的數(shù)組的數(shù)組索引操作。
有一個(gè)特殊的情況是,x
可能是一個(gè)復(fù)合字面量,復(fù)合字面量(結(jié)構(gòu)體字面量、數(shù)組字面量、切片字面量、映射字面量)是不可尋址的,但是依然可以使用&x
。對(duì)復(fù)合字面量進(jìn)行&x
操作,會(huì)生成一個(gè)指針,這個(gè)指針指向使用字面量的值進(jìn)行初始化的一個(gè)唯一變量。
如果對(duì)x
的計(jì)算會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤,那么對(duì)&x
的計(jì)算也會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。
var c float64 = 222.22 fmt.Println(&c) // 1. 對(duì)變量c進(jìn)行尋址操作 0xc0000b2008 var d *float64 = &c fmt.Println(&*d) // 2.對(duì)指針間接引用(*d)進(jìn)行尋址操作 0xc0000b2008 e := make([]string, 2) // 創(chuàng)建一個(gè)初始長(zhǎng)度為2的切片 e = []string{"e1", "e2"} fmt.Println(&e[1]) // 3. 對(duì)切片索引操作進(jìn)行尋址操作 0xc0000b8030 type F struct { a string b int } fmt.Println(&F{"a", 1}) // 4.對(duì)結(jié)構(gòu)體字面量進(jìn)行尋址操作 &{a 1} var f F = F{"b", 123} fmt.Println(&f.a) // 5. 對(duì)結(jié)構(gòu)體的字段選擇進(jìn)行尋址操作 0xc0000a4048 var g = [3]int{1, 2, 3} // 創(chuàng)建一個(gè)數(shù)組 fmt.Println(&g[0]) // 6. 對(duì)數(shù)組的索引操作進(jìn)行尋址操作 0xc0000ba000 fmt.Println(&[3]int{4, 5, 6}) // 7. 對(duì)數(shù)組字面量進(jìn)行尋址操作 &[4 5 6] // var h *int = nil // fmt.Println(*h) // 會(huì)導(dǎo)致一個(gè)運(yùn)行時(shí)錯(cuò)誤:panic: runtime error: invalid memory address or nil pointer dereference // fmt.Println(&*h) // 會(huì)導(dǎo)致一個(gè)運(yùn)行時(shí)錯(cuò)誤:panic: runtime error: invalid memory address or nil pointer dereference
練習(xí)3
var i int = 1 fmt.Println("i的地址", &i) // i的地址 0xc000016098 increase(i) // 函數(shù)內(nèi)部i的地址 0xc0000160b0 fmt.Println("i的值", i) // i的值 1 increaseV1(&i) // 函數(shù)內(nèi)部拿到的i的地址 0xc000016098 fmt.Println("i的值", i) // i的值 2 func increase(i int) { fmt.Println("函數(shù)內(nèi)部i的地址", &i) i++ } func increaseV1(ptrI *int) { fmt.Println("函數(shù)內(nèi)部拿到的i的地址", &*ptrI) *ptrI++ }
將變量作為參數(shù)傳遞到函數(shù)中的時(shí)候,函數(shù)會(huì)復(fù)制變量中的值到局部變量中,所以不會(huì)改變外部變量的值。
在調(diào)用increase(i)
時(shí),會(huì)創(chuàng)建一個(gè)新的局部變量i
,這個(gè)變量i
的作用域在函數(shù)內(nèi)部,初始化的值是復(fù)制的外部變量i
中的值。所以在函數(shù)內(nèi)部執(zhí)行i++
的時(shí)候,改變的是局部變量i
的值,不會(huì)影響到外部變量。執(zhí)行完之后外部的i
的值還是1
。
當(dāng)執(zhí)行increaseV1(&i)
時(shí),傳入的是一個(gè)指向外部i
的指針,它表示的地址是外部i
的地址0xc000016098
,所以在函數(shù)內(nèi)部執(zhí)行*ptrI++
時(shí),改變的是地址0xc000016098
中存儲(chǔ)的值,執(zhí)行完函數(shù)之后,打印外部的i
(代表內(nèi)存地址0xc000016098
)的值,發(fā)現(xiàn)值已經(jīng)變?yōu)?code>2了。
原文鏈接:https://juejin.cn/post/7100166142974492679
相關(guān)推薦
- 2022-08-25 pycharm中keras導(dǎo)入報(bào)錯(cuò)無(wú)法自動(dòng)補(bǔ)全cannot?find?reference分析_pyt
- 2022-09-20 Android畫(huà)圖實(shí)現(xiàn)MPAndroidchart折線圖示例詳解_Android
- 2021-12-09 golang中g(shù)in框架接入jwt使用token驗(yàn)證身份_Golang
- 2022-03-23 C語(yǔ)言新手初階教程之三子棋實(shí)現(xiàn)_C 語(yǔ)言
- 2022-09-05 Hbase 之KeyValue結(jié)構(gòu)詳解
- 2022-09-17 ASP.NET?Core實(shí)現(xiàn)AES-GCM加密算法_實(shí)用技巧
- 2022-09-17 docker資源控制管理Cgroup的實(shí)現(xiàn)_docker
- 2022-09-14 apache虛擬主機(jī)配置的三種方式(小結(jié))_Linux
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支