指针的定义

指针是一个代表着某个内存地址的值。这个内存地址往往是在内存中存储的另一个变量的值的起始位置。

go指针是提供操作数据的基本桥梁。因为go很多调用,往往复制一份对象,例如函数的参数,如果没有指针,有些情况不得不存在很多副本。

golang:指针理解总结

 

 

 Go语言保留了指针,但与C语言指针有所不同。主要体现在:

  • 默认值 nil
  • 操作符 "&" 取变量地址, "*" 通过指针访问标对象
  • 持指针运算,不 "->" 运算符,直接⽤ "." 访问目标成员

 概念: linux 程序内存管理

golang:指针理解总结

 

 

 

data section (.data)*: 用来存放已经被初始化为非零的全局变量。

bss section (.bbs):用来存放 没有被初始化 和 已经被初始化为0 的全局变量。

rodata section(.rodata): 用来存放常量数据。 ro: read only

text section(.text):存放代码(如:函数)和部分整数常量(应该指的是一些立即数),这个段是可执行的。

heap (堆):动态分配内存,由程序自身决定开辟和释放。

stack(栈): 存放函数的局部变量和函数参数

栈帧:用来给函数运行提供内存空间,取内存于stack上,当函数调用的时候,产生栈帧.函数调用结束的时候,释放栈帧。栈帧存储: 1.局部变量. 2形参(形参与局部变量存储地位相同) 3.内存字段描述值

如何使用指针

  • * 取值操作符
  • & 取指(指针)操作符

使用 var p *int 声明一个指针类型的变量,当一个指针被定义后没有分配到任何变量时,它的值为 nil。

func main()  {
   var a int = 100                // 声明 int 变量 a
   fmt.Printf("&a = %p\n", &a)    // "&" 取 a 地址

   var p *int       	// 声明变量p
   p = &a                	// p指向a
   fmt.Printf("p = %p\n", p)
   fmt.Printf("a = %d, *p = %d\n", a, *p)
   *p = 324                  	//*p操作指针所指向的内存,即为a
   fmt.Printf("a = %d, *p = %d\n", a, *p)
}

变量存储

左值(Lvalue)和右值(Rvalue)

左值(Lvalue):Location-value,表示可寻址。是保存在内存中,具有确切地址,并能取地址,进行访问,修改等操作的表达式。

右值(Rvalue):Read-value,表示可读不可寻址。是保存在内存中,或者寄存器中,不知道也无法获得其确切地址,在得到计算表达式结果后就销毁的临时表达式。

var a = 1 //a是左值
var b = 2 //b是左值
var c = a + b //这里a和b从左值转换为右值,然后将和(右值)赋值给左值c。

左值引用一般不能用右值初始化,因为如果用右值初始化,相当于将左值绑定在了右值上,那右值就不会被销毁,也就不是右值了

空指针和野指针

  • 空指针:没有存储任何内存地址的指针就称为空指针 go 为 nil
  • 野指针:不可用内存的指针

指针变量的零值不是空子串,而是nil。p的值是指针类型,由于尚未该指针尚未指向另外一个地址。因此初始化为nil。

var p *int
*p = 1  //错误,1是右值,p是左值引用,无法直接初始化

 

 *p = 1 的含义可以理解为,将nil的指针地址的值赋予1。可是p的值是nil,但还没有赋值成地址,因此不能把一个子串赋值给一个nil值。此外,即使不是赋值,对nil的指针通过*读取也会报错,毕竟读取不到任何地址。无效的赋值即野指针

golang:指针理解总结

 

 

 golang:指针理解总结

 

 

 函数new

表达式new(type)将创建一个type类型的匿名变量,所做的是为type类型的新值分配并清零一块内存空间,然后将这块内存空间的地址作为结果返回,而这个结果就是指向这个新的type类型值的指针值,返回的指针类型为*type。此时会在堆空间开辟一个内存地址。随应用程序使用始终存在。

 

package main

import "fmt"

func main() {

   var p *int

   p = new(int)  // 为p开辟一个int的地址, 初始为nil的地址

   *p = 100 // 此时可以正常赋值
   fmt.Println(p)
   fmt.Println(*p)
}

 golang:指针理解总结

  指针做函数参数

golang允许向函数传递指针,志需要在函数定义的参数上设置为指针类型即可。

 

值传递,将实参拷贝一份给形参

传地址(引用),将形参的地址值作为函数参数、返回值后传递

 func swap01(a, b int) {
    a, b = b, a
    fmt.Printf("swap01 a = %d, b = %d\n", a, b)
}

func swap02(x, y *int) {
    *x, *y = *y, *x
}

func main() {
    a := 10
    b := 20

    //swap01(a, b) 	//值传递(传值)
    swap02(&a, &b) 	//地址传递(传引用)
    fmt.Printf("a = %d, b = %d\n", a, b)
}

多级指针

一级指针:指向变量的地址
二级指针:指向一级指针的地址
....

 

package main

import "fmt"

func main() {
	var a = 10

	var b *int
	var c **int

	b = &a
	c = &b
	**c = 200

	fmt.Println(a, &a)
	fmt.Println(b, &b)
	fmt.Println(c, &c)
}

 golang:指针理解总结

 

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-11-03
  • 2021-06-11
  • 2022-12-23
  • 2021-09-07
  • 2022-01-31
猜你喜欢
  • 2022-01-21
  • 2021-06-25
  • 2021-12-15
  • 2021-06-16
  • 2021-06-18
  • 2021-10-03
相关资源
相似解决方案