Golang Go语言中的切片地址
Golang Go语言中的切片地址
func main() {
months := []string{1: “January”}
fmt.Printf("%p,\n",&months) //0xc0000ae040,
fmt.Printf("%p,\n",months) //0xc0000ae060,
fmt.Printf("%p,\n",&months[0]) //0xc0000ae060,
}
我知道第二个和第三个打印函数指向的是底层数组的第一个元素的地址。 但是我想问的是第一个打印函数中打印的地址指向的是什么? 对切片这个引用类型(本身传递的就是地址)取地址会取到什么呢?
(我在 stackoverflow 上看到回答是指向 slice 的 header 。我的疑惑是这个 header 如果表示的是 slice 结构体,但是 slice 结构体的第一个成员变量就是数组的指针,那么结构体的地址不就是第一个成员变量的地址吗,不就是底层数组的第一个元素吗?)
更多关于Golang Go语言中的切片地址的实战教程也可以访问 https://www.itying.com/category-94-b0.html
months 是一个指针变量,存一个地址,指向这个切片。
这个指针变量同样需要一个内存地址来存储。
int *p;
int a = 5;
p = &a;
p 存了 a 的地址,但 p 本身也需要一个内存地址来存储。
把 p 理解成一个 cpu 字长大小的整形变量,他存了一个整形地址。所以它也需要一个内存地址。
个人理解,如果有错感谢指正。
更多关于Golang Go语言中的切片地址的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
fmt.Printf(“0x%x\n”, (*reflect.SliceHeader)(unsafe.Pointer(&months)).Data)
第一个是指针自己的地址
func main() {
months := []string{1: “January”}
fmt.Printf("%p,\n", &months)
fmt.Printf("%p,\n", months)
fmt.Printf("%p,\n", &months[0])
header := (*reflect.SliceHeader)(unsafe.Pointer(&months))
fmt.Printf("%p,\n", header)
fmt.Printf(“0x%x,\n”, header.Data)
fmt.Printf(“0x%x,\n”, header.Data+0)
}
把你的代码翻译了一下,前面的几个打印语句等价于后面的三行
第一行打印 months 变量地址 (SliceHeader)
第二行从 months 变量地址处取一个指针变量的长度当做指针打印 (SliceHeader 开头也正好是 uintptr)
第三行打印 slice 指向的底层数组第一个元素地址
谢谢,理解了
谢谢,明白了
指针,和指针的指针
在Golang(Go语言)中,切片(slice)是一种动态数组,其底层实现是一个包含三个主要部分的数据结构:指向数组的指针(Pointer)、切片的长度(Length)和切片的容量(Capacity)。
当我们讨论切片的地址时,通常是指切片头(slice header)的地址,而不是切片所引用的底层数组元素的地址。切片头是一个结构体,包含上述三个字段。你可以通过&
操作符获取一个切片的地址,但这个地址实际上是指向切片头结构体的指针。
需要注意的是,即使两个切片引用的是同一个底层数组,并且长度和容量都相同,它们的切片头地址也可能是不同的,因为每个切片都有自己独立的切片头。
此外,切片是可以重新切片的(reslicing),这意味着你可以通过改变切片的起始位置和长度来创建一个新的切片,这个新切片会共享原切片的底层数组,但会有自己的切片头。
在Go语言中,切片的这种设计使得它们非常灵活和高效,但同时也需要开发者注意切片间的共享和内存管理,以避免潜在的内存泄漏或数据竞争问题。
总的来说,理解切片地址的概念对于深入掌握Go语言的内存模型和切片操作至关重要。在实际开发中,合理使用切片可以显著提升程序的性能和代码的可读性。