首页 > 其他分享 >【10.0】Go语言基础之指针

【10.0】Go语言基础之指针

时间:2023-11-12 12:11:55浏览次数:28  
标签:10.0 变量 反解 fmt Println 类型 Go 指针

【一】什么是指针

  • 指针是—种存储变量内存地址(Memory Address)的变量。

  • 如上图所示,变量b 的值为156 ,而b 的内存地址为0x1040a124。

    • 变量 α存储了b 的地址。
    • 我们就称a指向了b 。

【二】指针的定义

【1】指针的语法基础

  • 1 类型前放 * 表示指针类型,这个类型的指针,指向这个类型的指针
  • 2 在变量前加 & 取地址符号,表示取该变量的地址
  • 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

【2】指针的定义和使用

package main

import "fmt"

func main() {
	// 指针 :存储 变量内存地址  的  变量

	// 1 类型前放 *  表示指针类型,这个类型的指针,指向这个类型的指针
	// 2 在变量前加 & 取地址符号,表示取该变量的地址
	// 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

	// [1]定义一个int类型的变量
	var a int = 10

	// [2]定义一个变量,来存a的地址 : * 表示指针类型
	var p *int

	// [3]取地址 :& 表示取该变量的地址
	p = &a

	// 每一次程序运行申请的内存空间是不一致的,所以每次指针的指向地址也会跟着变化
	// 程序重启,内存空间大概率发生更改;程序不终止,当前内存地址不会发生变化
	fmt.Println("当前指针 p :>>>> ", p)
	// 当前指针 p :>>>>  0xc00001e0a8
	// 当前指针 p :>>>>  0xc0000a6058
}

【3】指针的指针

package main

import "fmt"

func main() {
	// 指针 :存储 变量内存地址  的  变量

	// 1 类型前放 *  表示指针类型,这个类型的指针,指向这个类型的指针
	// 2 在变量前加 & 取地址符号,表示取该变量的地址
	// 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

	// [1]定义一个int类型的变量
	var a int = 10

	// [2]定义一个变量,来存a的地址 : * 表示指针类型
	var p *int

	// [3]取地址 :& 表示取该变量的地址
	p = &a

	// 每一次程序运行申请的内存空间是不一致的,所以每次指针的指向地址也会跟着变化
	// 程序重启,内存空间大概率发生更改;程序不终止,当前内存地址不会发生变化
	fmt.Println("当前指针 p :>>>> ", p)
	// 当前指针 p :>>>>  0xc00001e0a8
	// 当前指针 p :>>>>  0xc0000a6058

	// [4]指针的指针
	var p1 **int = &p // 取一次加一个 *
	fmt.Println("当前指针 p1 :>>>> ", p1)
	var p2 ***int = &p1
	fmt.Println("当前指针 p2 :>>>> ", p2)

	//当前指针 p :>>>>  0xc00001e0a8
	//当前指针 p1 :>>>>  0xc00000a028
	//当前指针 p2 :>>>>  0xc00000a038
}

【4】指针反解

package main

import "fmt"

func main() {
	// 指针 :存储 变量内存地址  的  变量

	// 1 类型前放 *  表示指针类型,这个类型的指针,指向这个类型的指针
	// 2 在变量前加 & 取地址符号,表示取该变量的地址
	// 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

	// [1]定义一个int类型的变量
	var a int = 10

	// [2]定义一个变量,来存a的地址 : * 表示指针类型
	var p *int

	// [3]取地址 :& 表示取该变量的地址
	p = &a

	// 每一次程序运行申请的内存空间是不一致的,所以每次指针的指向地址也会跟着变化
	// 程序重启,内存空间大概率发生更改;程序不终止,当前内存地址不会发生变化
	fmt.Println("当前指针 p :>>>> ", p)
	// 当前指针 p :>>>>  0xc00001e0a8
	// 当前指针 p :>>>>  0xc0000a6058

	// [4]指针的指针
	var p1 **int = &p // 取一次加一个 *
	fmt.Println("当前指针 p1 :>>>> ", p1)
	var p2 ***int = &p1
	fmt.Println("当前指针 p2 :>>>> ", p2)

	//当前指针 p :>>>>  0xc00001e0a8
	//当前指针 p1 :>>>>  0xc00000a028
	//当前指针 p2 :>>>>  0xc00000a038

	// [5]地址反解成值 : 在(指针)变量前加 * 表示反解,把地址解析成具体的值
	fmt.Println("反解*p :>>>> ", *p)       // 反解指针变量 p 指向 a 解析出 a 的值
	fmt.Println("反解*p1 :>>>> ", *p1)     // 反解指针变量 p1 指向 p 解析出 p 的值
	fmt.Println("反解**p1 :>>>> ", **p1)   // 反解指针变量 p1 指向 p 再指向 a 解析出 a 的值
	fmt.Println("反解*p2 :>>>> ", *p2)     // 反解指针变量 p2 指向 p1 解析出 p1 的值
	fmt.Println("反解***p2 :>>>> ", ***p2) // 反解指针变量 p2 指向 p1 指向 p 再指向 a 解析出 a 的值

	//当前指针 p :>>>>  0xc00001e0a8
	//当前指针 p1 :>>>>  0xc00000a028
	//当前指针 p2 :>>>>  0xc00000a038
	//反解*p :>>>>  10
	//反解*p1 :>>>>  0xc00001e0a8
	//反解**p1 :>>>>  10
	//反解*p2 :>>>>  0xc00000a028
	//反解***p2 :>>>>  10
}

【5】指针类型的零值

package main

import "fmt"

func main() {
	// 指针 :存储 变量内存地址  的  变量

	// 1 类型前放 *  表示指针类型,这个类型的指针,指向这个类型的指针
	// 2 在变量前加 & 取地址符号,表示取该变量的地址
	// 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

	// [5] 指针的零值
	name := "Dream"
	var n *string

	fmt.Println("当前指针指向变量前 n :>>>> ", n)
	// 指针指向 变量 name 取值 &
	n = &name
	fmt.Println("当前指针指向变量后 n :>>>> ", n)

	//当前指针指向变量前 n :>>>>  <nil>
	//当前指针指向变量后 n :>>>>  0xc000088240
}

【6】指针是引用类型

package main

import "fmt"

func main() {
	// 指针 :存储 变量内存地址  的  变量

	// 1 类型前放 *  表示指针类型,这个类型的指针,指向这个类型的指针
	// 2 在变量前加 & 取地址符号,表示取该变量的地址
	// 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

	// 指针是引用类型 ----> 当参数传递
	a := 10 // var a int = 10
	p := &a // var p *int = &a

	// 调用函数
	foo(p)
	fmt.Println("函数调用后修改值 :>>>> ", *p)

	//反解指针类型 p :>>>>  10
	//函数内部修改值 :>>>>  99
	//函数调用后修改值 :>>>>  99
}

// 参数类型为 *int : 指针类型(指向 int 类型的指针)
func foo(p *int) {
	fmt.Println("反解指针类型 p :>>>> ", *p)

	// 修改值 : 并不是修改 p 的值,而是修改 p 指向的 a 的值
	*p = 99
	fmt.Println("函数内部修改值 :>>>> ", *p)
}

【7】不要向函数传递数组的指针,而应该使用切片

package main

import "fmt"

func main() {
	// 指针 :存储 变量内存地址  的  变量

	// 1 类型前放 *  表示指针类型,这个类型的指针,指向这个类型的指针
	// 2 在变量前加 & 取地址符号,表示取该变量的地址
	// 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

	// 不要向函数传递数组的指针,而应该使用切片
	var name = [3]string{"梦梦", "蚩梦", "小梦"}

	// 调用函数 : 不要向函数传递数组的指针
	foo(&name) // 把 数组 name 的地址取出来 ---> 变成了 指针类型指向 name
	fmt.Println("函数外修改后的数组 :>>>> ", name)

	//取值 p[1] :>>>>  蚩梦
	//函数内修改后的数组 :>>>>  [醉梦 蚩梦 小梦]
	//函数外修改后的数组 :>>>>  [醉梦 蚩梦 小梦]

	var a []string = name[:]
	// 调用函数 : 传切片进去
	bar(a)
	fmt.Println("函数外修改后的切片 :>>>> ", a)
	fmt.Println("函数外修改后的数组 :>>>> ", name)

	//取值 o[1] :>>>>  蚩梦
	//函数内修改后的数组 :>>>>  [晓梦 蚩梦 小梦]
	//函数外修改后的切片 :>>>>  [晓梦 蚩梦 小梦]
	//函数外修改后的数组 :>>>>  [晓梦 蚩梦 小梦]

	// 总结 :
	//	使用切片的好处是,如果数组长度变了,函数不需要重写
	//	如果是数组,需要重写再写一个函数对应
}

// 参数类型为 *int : 指针类型(指向 int 类型的指针)
func foo(p *[3]string) {
	// (*p)[1] ----> 先对 p 解引用 变成数组, 再对 p 取值
	fmt.Println("取值 p[1] :>>>> ", (*p)[1])
	// 修改值
	(*p)[0] = "醉梦"
	fmt.Println("函数内修改后的数组 :>>>> ", *p)
}

// 参数类型为 o []string : 切片类型
func bar(o []string) {

	// (*p)[1] ----> 先对 p 解引用 变成数组, 再对 p 取值
	fmt.Println("取值 o[1] :>>>> ", o[1])
	// 修改值
	o[0] = "晓梦"
	fmt.Println("函数内修改后的数组 :>>>> ", o)
}

【8】数组的指针不需要解引用

package main

import "fmt"

func main() {
	// 指针 :存储 变量内存地址  的  变量

	// 1 类型前放 *  表示指针类型,这个类型的指针,指向这个类型的指针
	// 2 在变量前加 & 取地址符号,表示取该变量的地址
	// 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

	// 如果是数组的指针,不需要解引用,直接使用即可,按索引取值即可
	var a = [3]int{7, 8, 9}
	var p *[3]int = &a

	fmt.Println("解引用再取值 :>>>> ", (*p)[0])
	fmt.Println("不需要解引用再取值 :>>>> ", p[0]) // 支持直接按索引取值
	fmt.Println("取 p  :>>>> ", p)         // &[7 8 9]

	//解引用再取值 :>>>>  7
	//不需要解引用再取值 :>>>>  7
	//取 p  :>>>>  &[7 8 9]
}

【9】不支持指针运算

package main

import "fmt"

func main() {
	// 指针 :存储 变量内存地址  的  变量

	// 1 类型前放 *  表示指针类型,这个类型的指针,指向这个类型的指针
	// 2 在变量前加 & 取地址符号,表示取该变量的地址
	// 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

	// go 语言不支持指针运算
	var a = [3]int{7, 8, 9}
	var p *[3]int = &a

	// p++ : 在 c 语言中表示 p[1]
	fmt.Println("指针运算 :>>>> ", p++) // ')', ',' or '...' expected, got '++'
}

【10】指针数组和数组指针

package main

import "fmt"

func main() {
	// 指针 :存储 变量内存地址  的  变量

	// 1 类型前放 *  表示指针类型,这个类型的指针,指向这个类型的指针
	// 2 在变量前加 & 取地址符号,表示取该变量的地址
	// 3 在(指针)变量前加 * 表示反解,把地址解析成具体的值

	// 指针数组(数组里放了一堆指针)和数组指针(指向数组的指针)

	// 定义数组
	var a = [3]int{7, 8, 9}

	// 定义指针 指向数组 --- 数组指针
	var p *[3]int = &a
	fmt.Println("这是定义的数组指针 p :>>>> ", p)
	// 这是定义的数组指针 p :>>>>  &[7 8 9]

	// 定义数组 , 数组内的类型 为 指针类型 ----> 指针数组
	var x, y, z = 4, 5, 6
	var b [3]*int = [3]*int{&x, &y, &z}
	fmt.Println("这是定义的指针数组  b :>>>> ", b)
	// 这是定义的指针数组  b :>>>>  [0xc0000a6090 0xc0000a6098 0xc0000a60a0]
}

标签:10.0,变量,反解,fmt,Println,类型,Go,指针
From: https://www.cnblogs.com/dream-ze/p/17826952.html

相关文章

  • Go语言爬虫框架colly简析
    一、简介随着互联网的快速发展,数据已经成为了一种非常重要的资源,各类用户都需要通过爬虫来获取所需的数据。在众多的编程语言中,Go语言以其高效、简洁、并发等特性,成为越来越优选的编程语言,并且在爬虫领域也有着广泛应用。在爬虫框架领域,各流行编程语言都有自己热门框架,如Python中的......
  • C语言之指针(下)
    指针数组与多级指针指针数组由于指针本身也是变量,所以一组同类指针也可以像其它变量一样形成一个数组。如果一个数组的元素均为某一类型的指针,则称该数组为指针数组。语法如下:类型名*数组名[数组长度];char*string[10];案例:编写一个函数,用二分法查找某一个城市名在城市表中是否......
  • 【6.0】Go语言基础之循环语句
    【一】判断语句if~elsepackagemainimport"fmt"//if~else的使用//[1]语法//语法if条件{条件符合,执行代码}//语法elseif条件{条件符合,执行代码}//语法else{条件符合,执行代码}//[2]执行代码的左侧{必须跟关键字在同一行funcmain(){ score:......
  • 【5.0】Go语言基础之包的使用
    【一】包的作用为了便于组织代码,同一种类型的代码,写在同一个包下,便于管理【二】定义包的步骤【1】新建一个文件夹【2】内部有很多go文件【3】go文件的第一行声明包名在每个go文件的第一行,都要声明包名,并且包名必须一致packageuser【4】在一个文件夹下只能有一个包(......
  • 【8.0】Go语言基础之可变函数参数、map的使用
    【一】可变长参数【1】任意长度的指定类型的参数packagemainimport"fmt"funcmain(){ //可变长参数 //调用函数 foo(1,2,3,4,5,6) //这是接收到的参数a:>>>>[123456] //这是接收到的参数a的类型:>>>>[]int}//可以接收任意长度的int类......
  • 【7.0】Go语言基础之数组、切片
    【一】数组数组是一种类型,可以连续存储数据,但是数据类型的是一致的。类似于Python中的列表,是一种数据结构【1】数组的定义packagemainimport"fmt"funcmain(){ //定义数组 //定义一个长度为3的数组,里面的数据类型为int类型 //定义好数组以后,大小就固......
  • Golang布隆过滤器升级版
    作用:平常使用的布隆过滤器可以用来过滤Redis空数据,避免缓存穿透。升级点:将原本的bool数组位更改为int数组,实现便于删除操作的场景。代码如下:packagemainimport( "fmt")//BloomFilter布隆过滤器typeBloomFilterstruct{ bitArray[]int//升级版结构哈希所落位置+......
  • 2023-11-11:用go语言,字符串哈希+二分的例题。 给定长为 n 的源串 s,以及长度为 m 的模式
    2023-11-11:用go语言,字符串哈希+二分的例题。给定长为n的源串s,以及长度为m的模式串p,要求查找源串中有多少子串与模式串匹配,s'与s匹配,当且仅当s'与s长度相同,且最多有k个位置字符不同。其中1<=n,m<=10^6,0<=k<=5。来自左程云。答案2023-11-11:go代码用灵捷3.5......
  • 2023-11-11:用go语言,字符串哈希+二分的例题。 给定长为 n 的源串 s,以及长度为 m 的模式
    2023-11-11:用go语言,字符串哈希+二分的例题。给定长为n的源串s,以及长度为m的模式串p,要求查找源串中有多少子串与模式串匹配,s'与s匹配,当且仅当s'与s长度相同,且最多有k个位置字符不同。其中1<=n,m<=10^6,0<=k<=5。来自左程云。答案2023-11-11:go代码用......
  • Go实现Zabbix企业微信应用通知告警
    企业微信https://work.weixin.qq.com/企业微信->应用管理->创建应用个人微信也能接收企业微信信息我的企业->微信插件->扫码关注特殊说明之前企业微信只需要调用接口就能实现微信应用通知,最近改版,变得比较复杂1:需要配置可信IP才能发2:配置可信IP前需要先设置可信域名......