go语言中内存地址(指针) 与new和make的区别
golang中,每一个变量在内存中都有一个对应的内存地址。
获取变量的内存地址 %p &变量名
package main
import ("fmt")
func main() {
// 内存地址通过[&变量名]来获取;占位符使用[%p]
var a int = 10
// 内存地址0x13443e40090
fmt.Printf("内存地址%p", &a)
}
指针
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置
指针也是一个变量,但它是一种特殊的变量,
它存储的数据不是一个普通的值,而是一个变量的内存地址。
代表指针;int, *strig 类型
通过[&变量名]来获取变量的内存地址
package main
import ("fmt")
func main() {
// 内存地址通过[&变量名]来获取;占位符使用[%p]
var a int = 10
// 内存地址0x13443e40090
fmt.Printf("值是:%v, 类型是:%T,内存地址:%p\n",a,a, &a)
//将内存地址赋值给b
var b = &a
fmt.Printf("值是:%v, 类型是:%T,内存地址:%p",b,b, b)
}
值是:10, 类型是:int,内存地址:0x1d0a0f3ca090
值是:0x1d0a0f3ca090, 类型是:*int,内存地址:0x1d0a0f3ca090
我们发现他们的内存地址是一样的
通过内存地址获取变量的值
package main
import ("fmt")
func main() {
var a int = 10
// 通过 &变量名来获取变量的内存地址,p是变量a的内存地址
p := &a
// 输出内存地址: 0xd146712c090
fmt.Println(p)
// 通过内存地址来获取变量的值;输出的是:10
fmt.Println(*p)
}
*p表示:某个内存地址所对应的值;
*p = 20 表示将这个内存地址对应的值改为20
&变量名: 表示变量的内存地址,也叫做指针
通过指针修改变量的值(通过更改内存地址来修改变量的值)
package main
import ("fmt")
func main() {
var a int = 10
// 通过 &变量名来获取变量的内存地址,p是变量a的内存地址
p := &a
*p = 20
// 输出的值是:20
fmt.Println(a)
}
package main
import ("fmt")
func fn1(x int){
x = 20
}
func fn2(x *int){
*x = 40
}
func main() {
var a =1
fn1(a)
fmt.Println(a) // 此时a的值还是1
fn2(&a)
fmt.Println(a) // 此时a的值变成了40
}
指针的两大核心用途:
修改原值:如果你希望在函数内部修改外部的变量(就像案例中的 fn2),就必须传递该变量的指针。
提升性能:当传递非常大的结构体(Struct)或数组时,值传递会复制整个数据,消耗大量内存和 CPU;
而传递指针只需要复制一个很小的地址(通常 8 字节),能极大降低拷贝开销。
为啥会报错呢
package main
import ("fmt")
func main() {
// 定义一个指针变量 a
var a *int
// 将这个指针的值设置为 10
*a = 10
// 输出这个指针的值
fmt.Println(*a)
}
大家认为会输出什么?
有的小伙伴认为会输出10,但是实际上是会报错的。
因为:我先定义一个指针变量 a,这里没有问题。
在 Go 语言中,变量声明后如果没有显式赋值,会自动赋予该类型的零值。
指针类型的零值是 nil。此时a 的值为 nil。这意味着此时 a 并没有指向任何有效的内存地址。
当我使用 *a 试图向这个指针[指向的内存地址]写入 10 时,
由于 a 是 nil(空的),程序找不到实际的内存空间来存放这个值。
Go 的运行时就会报错。
如何解决:要让指针能够存储数据,必须先为它分配一块合法的内存空间。在 Go 中有两种常见方式:
new 和 make 是内建的两个函数,主要用来分配内存
分配内存
在 Go语言中对于引用类型的变量,我们在使用的时候不仅要声明它。
还要为它分配内存空间,否则我们的值就没办法存储。
而对于值类型的数据不需要分配内存家间,是因为它们在声明的时候已经默认分配好了内存空间。
要分配内存,就引出来今天的 new 和 make。
Go 语言中 new 和 make 是内建的两个函数,主要用来分配内存
1. 使用 new 函数(推荐)
package main
import "fmt"
func main() {
// 使用 new 为 int 分配内存,此时 a 指向一个值为 0 的 int 变量
var a *int = new(int)
*a = 10 // 现在可以安全地修改它指向的值了
fmt.Println(*a) // 输出: 10
}
总结:在 Go 语言中,指针、切片(slice)、映射(map)等引用类型如果只声明不初始化,它们的零值都是 nil
在说一下:指针也是引用类型,所以指针的零值也是 nil
使用 new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。举个例子:
内存地址,类型,内存地址对应的值
package main
import ("fmt")
func main() {
// a是一个指针变量,类型是 *int 的指针类型,指针变量对应的值是0
var a = new(int)
fmt.Printf("值是一个内存地址%v \n", a)
fmt.Printf("值是的类型%T \n", a)
fmt.Printf("指针内存地址对应的值%v \n", *a)
}
值是一个内存地址0x2f648759e090
值是的类型*int
指针内存地址对应的值0
ps: *变量名称表示:内存地址对应的值
&变量名称表示:取这个变量对应的内存地址
make
make 也是用于内存分配的,区别于 new,它只用于 lice(切片)、map(数组) 以及 channel 的内存创建
new 与 make 的相同点
二者都是用来做内存分配的。
new 与 make 的不同点
make 只用于 slice、map 以及 chpnnel 的初始化,返回的还是这三个引用类型本身
而 new 用于类型的内存分配,并且内存对应的值为类型零值
出处:https://www.cnblogs.com/ishoulgodo/
想问问题,打赏了卑微的博主,求求你备注一下的扣扣或者微信;这样我好联系你;(っ•̀ω•́)っ✎⁾⁾!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,或者关注博主,在此感谢!
万水千山总是情,打赏5毛买辣条行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主(っ•̀ω•́)っ✎⁾⁾!
想问问题,打赏了卑微的博主,求求你备注一下的扣扣或者微信;这样我好联系你;(っ•̀ω•́)っ✎⁾⁾!
如果文中有什么错误,欢迎指出。以免更多的人被误导。

浙公网安备 33010602011771号