news 2026/6/15 7:54:34

go语言指针详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
go语言指针详解

两个常用的符号

  • &取地址符
  • *取指针存的地址中的内容(指针中存的是某个内存地址,用*指针变量取出的是这个地址中存的内容)

指针的概念

指针=内存地址如果指针没有限制,那它可以指向内存中的任何位置

a内存地址 0x12345678, 值:100 var a int = 100

*b指针变量,指向了一个内存地址 0x12345678(a的内存地址)

指针变量b中存了变量a的地址。这个就是b指向了a

varaint=100

varb= &a

fmt.Println("a本身的内存地址:", &a)//0xc00008c0a8

fmt.Println("b内存中存储的地址:",b)//0xc00008c0a8

fmt.Println("b本身的内存地址:", &b)//0xc00008e060

fmt.Println("b内存中存储的地址中的值", *b)//100

此时a和b内存中存储的地址是指向的同一个内存空间,所以修改了*b a 和 *b都会改变(可以看做这时a == *b)

*b=2000

fmt.Println("a",a)

fmt.Println("*b", *b)

指针如何使用

变量定义

varaint=100

指针变量的定义 正规的定义方式

varb*int= &a

指针变量的定义 偷懒的方式

c:= &a

fmt.Println("a的值",a)//100

fmt.Println("a的内存地址", &a)//0xc00000a0e8

fmt.Println("b变量中存的地址",b)//0xc00000a0e8

fmt.Println("b变量自己的内存地址", &b)//0xc000054068

fmt.Println("b变量中存的地址中的值", *b)//100

fmt.Println("c变量中存的地址",c)//0xc00000a0e8

fmt.Println("c变量自己的内存地址", &c)//0xc000054070

fmt.Println("c变量中存的地址中的值", *c)//100

通过指针b或指针c都可以改变a的值

*c=123

fmt.Println(a)

多级指针的使用(套娃)

多级指针:指针的套娃,指针指向指针 , 指针类型 第一个*指针类型, *int是这个指针对应的类型

如何理解多个符号,第一个取出来后,后面就是它的类型 *(*(*(int)))

例如:*ptr3 的类型就是 **int **ptr3 的类型就是*int ***ptr的类型就是int

varaint=100

varptr1*int= &a

varptr2**int= &ptr1

varptr3***int= &ptr2

fmt.Println("a的内存地址", &a)//0xc00000a0e8

fmt.Println("-----------------------------------------------")

fmt.Println("ptr1变量中存的内存地址",ptr1)//0xc00000a0e8

fmt.Println("ptr1变量自己的内存地址", &ptr1)//0xc000054068

fmt.Println("-----------------------------------------------")

fmt.Println("ptr2变量中存的内存地址",ptr2)//0xc000054068

fmt.Println("ptr2变量中存的内存地址中存的内存地址", *ptr2)//0xc00000a0e8

fmt.Println("ptr2变量自己的内存地址", &ptr2)//0xc000054070

fmt.Println("-----------------------------------------------")

fmt.Println("ptr3变量中存的内存地址",ptr3)//0xc000054070

fmt.Println("ptr3变量中存的内存地址中存的内存地址", *ptr3)//0xc000054068

fmt.Println("ptr3变量中存的内存地址中存的内存地址中存的内存地址", **ptr3)//0xc00000a0e8

fmt.Println("ptr3变量自己的内存地址", &ptr3)//0xc000054078

fmt.Printf("%T\n", *ptr3)

fmt.Printf("%T\n", **ptr3)

fmt.Printf("%T\n", ***ptr3)

//这时候改变a值的方式就很多了 因为*ptr1 **ptr2 ***ptr3 和 a 都是等价的,因为操控的是同一片内存空间

*ptr1=2000

fmt.Println(a)

**ptr2=3000

fmt.Println(a)

***ptr3=4000

fmt.Println(a)

数组指针

数组指针首先它是一个指针,然后指向了一个数组

定义一个数组

vararr= [4]int{1,2,3,4}

fmt.Println(arr)

fmt.Printf("数组的地址:%p\n", &arr)//0xc0000121c0

定义一个数组指针 指向数组

varptr_arr*[4]int= &arr

fmt.Println(ptr_arr)//&[1 2 3 4]

fmt.Println("取出内容:", *ptr_arr)//[1 2 3 4] 这时*ptr_arr == arr

fmt.Printf("ptr_arr变量中存的地址:%p\n",ptr_arr)//0xc0000121c0

fmt.Printf("ptr_arr变量自己的地址%p\n", &ptr_arr)//0xc000054070

通过指针操作数组 原生的操作方法

(*ptr_arr)[0] =100

fmt.Println(arr)//[100 2 3 4]

作为21世纪的新兴语言 不允许有这么的丑的代码出现

由于ptr_arr指向了arr 所以就出现了语法糖 可以像正常操作数组一样操作数组指针

ptr_arr[0] =123

fmt.Println(arr)

但这里需要注意的是,虽然因为语法糖的关系,可以用相同的方法操作。

但是它们的类型还是有本质区别的,一个是数组类型[4]int,一个是数组指针类型*[4]int

fmt.Printf("arr的类型%T\n",arr)//[4]int

fmt.Printf("ptr_arr的类型%T\n",ptr_arr)//*[4]int

指针数组

指针数组首先它是一个数组,数组里的每个元素保存的都是指针

a:=100

b:=200

c:=300

d:=400

创建一个指针数组,数组中存放的都是变量的地址

注意数组指针跟指针数组的区别: 数组指针*[4]int 指针数组[4]*int

ptr_arr:= [4]*int{&a, &b, &c, &d}

fmt.Println(ptr_arr)//[0xc00008c0a8 0xc00008c0c0 0xc00008c0c8 0xc00008c0d0]

通过指针修改变量的值

fmt.Println(a,b,c,d)//100 200 300 400

*ptr_arr[0] =666因为数组中的每个元素都是指针,所以要取出每个值都需要在取出元素的时候在前面再加上*号

fmt.Println(a,b,c,d)//666 200 300 400

指针函数

首先需要是一个函数,这个函数的返回值是一个指针

funcmain() {

调用了这个函数,可以得到一个指针类型的返回值

ptr:=fn()

fmt.Printf("ptr的类型:%T\n",ptr)//*[4]int

fmt.Printf("ptr的地址:%p\n", &ptr)//0xc00008e060

fmt.Println("ptr中的值:", *ptr)//[1 2 3 4]

回顾数组指针的操作方式(语法糖),我们就可以来愉快的操作这个数组了

fmt.Println((*ptr)[0])//原始的操作方式

ptr[0] =666//香香的语法糖

fmt.Println(ptr[0])

}

这个函数的返回值是一个指针

funcfn() *[4]int{

arr:= [4]int{1,2,3,4}

return&arr

}

指针作为函数参数

funcmain() {

a:=100

fmt.Printf("a变量的地址:%p\n", &a)//0xc00000a0e8

fmt.Printf("进入函数前 a的值 =%d\n",a)

updata1(a)

这里可以看出 因为值类型是拷贝的关系,并不会因为函数体内改变了a的值而改变a本身的值

fmt.Printf("函数结束后 a的值 =%d\n",a)

fmt.Printf("进入函数前 a的值 =%d\n",a)

updata2(&a)

这里可以看出 因为指针是引用类型传入的是地址,所以函数体内改变了a的值导致a本身的值也被改变了

fmt.Printf("函数结束后 a的值 =%d\n",a)

}

funcupdata1(aint) {

fmt.Println("--->",a)

fmt.Printf("a变量中的地址:%p\n", &a)//0xc00000a110

a=666

fmt.Println("--->",a)

}

funcupdata2(ptr*int) {

fmt.Println("--->", *ptr)

fmt.Printf("ptr变量中的地址:%p\n",ptr)//0xc00000a0e8

*ptr=666

fmt.Println("--->", *ptr)

}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 21:07:34

Gittyup:终极图形化Git客户端完整使用指南

Gittyup:终极图形化Git客户端完整使用指南 【免费下载链接】Gittyup Understand your Git history! 项目地址: https://gitcode.com/gh_mirrors/gi/Gittyup 你是否曾经在复杂的Git命令面前感到困惑?是否希望有一个更直观的方式来管理你的代码历史…

作者头像 李华
网站建设 2026/6/14 2:55:48

Markdown电子书制作终极指南:从零到专业出版

Markdown电子书制作终极指南:从零到专业出版 【免费下载链接】markdown-preview-enhanced One of the BEST markdown preview extensions for Atom editor! 项目地址: https://gitcode.com/gh_mirrors/ma/markdown-preview-enhanced 想要将Markdown文档快速转…

作者头像 李华
网站建设 2026/6/10 16:18:10

Wan2.2-T2V-A14B如何确保不同设备播放的兼容性?

Wan2.2-T2V-A14B 如何让生成的视频“在哪都能播”? 你有没有遇到过这种情况:辛辛苦苦用AI生成了一段惊艳的视频,结果发给客户一看——“打不开啊!”、“安卓手机黑屏”、“Safari提示不支持格式”…… 😣 这可不是个例…

作者头像 李华
网站建设 2026/6/14 5:35:56

PyMC终极指南:5步掌握Python贝叶斯建模

PyMC终极指南:5步掌握Python贝叶斯建模 【免费下载链接】pymc Python 中的贝叶斯建模和概率编程。 项目地址: https://gitcode.com/GitHub_Trending/py/pymc 还在为传统统计方法的局限性而困扰吗?想要用Python轻松实现贝叶斯推理和概率编程吗&…

作者头像 李华
网站建设 2026/6/15 17:23:02

dependency-cruiser扩展开发终极指南:如何轻松支持新编程语言

dependency-cruiser扩展开发终极指南:如何轻松支持新编程语言 【免费下载链接】dependency-cruiser Validate and visualize dependencies. Your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD. 项目地址: https://gitcode.com/gh_mirrors/de…

作者头像 李华
网站建设 2026/6/14 21:54:50

Wan2.2-T2V-A14B的美学优化机制:让AI生成视频更具艺术感

Wan2.2-T2V-A14B的美学优化机制:让AI生成视频更具艺术感 你有没有遇到过这样的情况——输入一段诗意的文字,比如“穿汉服的女孩站在樱花树下,微风拂过花瓣飘落”,点击生成,结果出来的视频虽然动作连贯、人物清晰&#…

作者头像 李华