Golang 指针

文章目录

  • 引言
  • 一、指针地址和指针类型
    • 1. 什么是指针
    • 2. 指针的使用
    • 3. 空指针
  • 二、指针数组
    • 1. 定义长度为3的整形数组
    • 2. 声明整形指针数组
  • 三、指向指针的指针
    • 1. 概述
    • 2. 示例
    • 3. 多重指针
  • 四、指针作为函数参数
  • 总结


引言

  Go 语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。
传递数据使用指针,而无须拷贝数据。Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)*(根据地址取值)


一、指针地址和指针类型

1. 什么是指针

  • 一个指针变量指向了一个值的内存地址,类似于变量和常量,在使用指针前你需要声明指针。
  • 指针声明格式如下:
var var_name *var-type

var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针

  • 以下是有效的指针声明:
var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮点型 */
  • 每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。使用&字符放在变量前面对变量进行“取地址”操作。 Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int、*int64、*string 等。

2. 指针的使用

  • 指针使用流程:
    ① 定义指针变量
    ② 为指针变量赋值
    ③ 访问指针变量中指向地址的值

  • 在指针类型前面加上*号(前缀)来获取指针所指向的内容:

package main

import "fmt"

func main() {

	var (
		a  int  = 18 //声明实际变量
		ip *int      //声明指针变量
	)

	ip = &a //把a的地址赋给ip指针
	fmt.Println("a变量的值是: ", a)
	fmt.Println("a变量的地址是: ", &a)
	fmt.Println("指针ip的值为: ", ip)
	fmt.Println("指针ip指向的值为: ", *ip)
}

//输出结果如下
a变量的值是:  18
a变量的地址是:  0xc0000aa058
指针ip的值为:  0xc0000aa058
指针ip指向的值为:  18

3. 空指针

  • 当一个指针被定义后没有分配到任何变量时,它的值为nil

  • nil 指针也称为空指针 ,一个指针变量通常缩写为 ptr

示例

package main

import "fmt"

func main() {
	var ptr *int
	fmt.Printf("ptr: %v\n", ptr)
	if ptr == nil {
		fmt.Println("ptr是空指针")
	} else {
		fmt.Println("ptr不是空指针")
	}
}


//输出结果如下
ptr: <nil>
ptr是空指针

二、指针数组

1. 定义长度为3的整形数组

package main

import "fmt"

func main() {
	a := []int{10, 20, 30}
	for i := 0; i < len(a); i++ {
		fmt.Printf("a[%d] = %d\n", i, a[i])
	}
}


//输出结果如下
a[0] = 10
a[1] = 20
a[2] = 30

2. 声明整形指针数组

var ptr [MAX] *int
  • ptr 为整形指针数组,因此每个元素都指向了一个值,下面示例中的三个整数将存储在指针数组中
package main

import "fmt"

func main() {
	a := []int{10, 20, 30} //世纪数组
	var ptr [3]*int        //指针数组申明
	//对实际数组进行遍历
	for i := 0; i < len(a); i++ {
		ptr[i] = &a[i] //整数的地址赋值给指针数组
		fmt.Printf("第%d个元素的指针地址%d\n", i, &a[i])
	}
	//使用指针变量指向值进行遍历
	for j := 0; j < len(ptr); j++ {
		fmt.Printf("a[%d] = %d\n", j, *ptr[j])
	}
}


//输出结果0个元素的指针地址8246344336561个元素的指针地址8246344336642个元素的指针地址824634433672
a[0] = 10
a[1] = 20
a[2] = 30

三、指向指针的指针

1. 概述

  • 如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量

  • 当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:

在这里插入图片描述

  • 指向指针的指针变量声明格式如下:
var ptr **int;

2. 示例

访问指向指针的指针变量指需要使用两个*

package main

import "fmt"

func main() {
	var (
		a    int   //变量
		ptr  *int  //指针
		pptr **int //指向指针的指针
	)
	a = 100 //变量赋值

	//指针ptr地址
	ptr = &a

	//指向指针ptr地址
	pptr = &ptr

	//获取pptr的值
	fmt.Printf("变量a = %d\n", a)
	fmt.Println("变量a的地址 =", &a)
	fmt.Printf("指针变量 *ptr = %d\n", *ptr)
	fmt.Println("指针pptr指向的值", *pptr)
	fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
	fmt.Println("pptr指针的地址 =", &pptr)
}


//输出结果
变量a = 100
变量a的地址 = 0xc0000aa058
指针变量 *ptr = 100
指针pptr指向的值 0xc0000aa058
指向指针的指针变量 **pptr = 100
pptr指针的地址 = 0xc0000ce020

3. 多重指针

pt3——》pto——》ptr——》变量a

package main

import "fmt"

func main() {
	var (
		//变量a
		a int = 5

		//把ptr指针指向变量a所在地址
		ptr *int = &a

		//开辟一个新的指针,指向ptr指针所指向的地址
		pts *int = ptr

		//二级指针,指向一个地址,这个地址存储的是一级指针的地址
		pto **int = &ptr

		//三级指针,指向一个地址,这个地址存储的是二级指针的地址
		pt3 ***int = &pto
	)
	fmt.Println("a的地址: ", &a)
	fmt.Println("a的值: ", a)
	fmt.Println("-----------------------------")
	fmt.Println("ptr指针所在的地址: ", &ptr)
	fmt.Println("ptr指针指向的地址: ", ptr)
	fmt.Println("ptr指针指向地址所对应的值: ", *ptr)
	fmt.Println("-----------------------------")
	fmt.Println("pts指针所在的地址: ", &pts)
	fmt.Println("pts指针指向的地址: ", pts)
	fmt.Println("pts指针指向地址所对应的值: ", *pts)
	fmt.Println("-----------------------------")
	fmt.Println("pto指针所在地址: ", &pto)
	fmt.Println("pto指针指向的指针(ptr)的存储地址", pto)
	fmt.Println("pto指针指向的指针(ptr)所指向的地址: ", *pto)
	fmt.Println("pto指针最终指向的地址对应的值: ", **pto)
	fmt.Println("------------------------------")
	fmt.Println("pt3指针所在的地址: ", &pt3)
	fmt.Println("pt3指针指向的指针(pto)的地址", pt3)                      //等于&*pt3
	fmt.Println("pt3指针指向的指针(pto)所指向的指针(ptr)的地址: ", *pt3)        //等于&**pt3
	fmt.Println("pt3指针指向的指针(pto)所指向的指针(ptr)所指向的地址(a): ", **pt3) //等于&***pt3
	fmt.Println("pt3指针最终指向的地址(a)对应的值: ", ***pt3)
}

输出结果如下

a的地址:  0xc0000140a8
a的值:  5
-----------------------------
ptr指针所在的地址:  0xc000006028
ptr指针指向的地址:  0xc0000140a8
ptr指针指向地址所对应的值:  5
-----------------------------
pts指针所在的地址:  0xc000006030
pts指针指向的地址:  0xc0000140a8
pts指针指向地址所对应的值:  5
-----------------------------
pto指针所在地址:  0xc000006038
pto指针指向的指针(ptr)的存储地址 0xc000006028
pto指针指向的指针(ptr)所指向的地址:  0xc0000140a8
pto指针最终指向的地址对应的值:  5
------------------------------
pt3指针所在的地址:  0xc000006040
pt3指针指向的指针(pto)的地址 0xc000006038
pt3指针指向的指针(pto)所指向的指针(ptr)的地址:  0xc000006028
pt3指针指向的指针(pto)所指向的指针(ptr)所指向的地址(a):  0xc0000140a8
pt3指针最终指向的地址(a)对应的值:  5

四、指针作为函数参数

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

  • 向函数传递指针,并在函数调用后修改函数内的值
package main

import "fmt"

func main() {
	var (
		a int = 100
		b int = 300
	)
	fmt.Printf("交换前a的值: %d\n", a)
	fmt.Printf("交换前b的值: %d\n\n", b)

	swap(&a, &b)

	fmt.Printf("交换后a的值: %d\n", a)
	fmt.Printf("交换后b的值: %d\n", b)
}

func swap(x, y *int) {
	//值传递,两数交换
	*x, *y = *y, *x
}


//输出结果如下
交换前a的值: 100
交换前b的值: 300

交换后a的值: 300
交换后b的值: 100

总结

  • 取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
    1.对变量进行取地址(&)操作,可以获得这个变量的指针变量。
    2.指针变量的值是指针地址。
    3.对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。

你可能感兴趣的:(Golang,golang,开发语言,go)