当前位置: 首页 > news >正文

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)

}

http://www.cnnetsun.cn/news/6849.html

相关文章:

  • 手把手教你用VSCode远程调试量子程序,10分钟快速上手
  • PC小说阅读器终极免费版:打造个性化数字阅读体验
  • 2025全新IDM使用方案:小白也能轻松掌握的终极指南
  • 全开源20亿参数大模型,揭秘清华团队如何突破资源限制训练LLM
  • 深度解析:4大维度构建量化因子归因的实战框架
  • YOLOv5模型瘦身实战:三大轻量化技术深度解析
  • SpringBoot
  • AH40G10是40V 10A双N+P沟道增强型MOSFET
  • 为什么顶尖开发者都在用VSCode做量子编程?真相曝光
  • note-gen AI笔记应用快速上手:10分钟掌握高效知识管理技巧
  • 东莞自动化设备工厂8个solidworks、caxa研发共用一台服务器
  • 全球国家编码数据宝库:一站式解决国际标准化需求 [特殊字符]
  • aio-switch-updater终极指南:Nintendo Switch定制化完全教程
  • Wan2.2-T2V-5B可用于博物馆展品动态复原展示
  • typing和dataclass
  • MindSpore网络编译问题BuildModel error 134
  • 拼多多PHP SDK:5分钟搞定电商API集成,让开发效率翻倍 [特殊字符]
  • Node-RED Dashboard实战指南:零基础构建专业数据可视化界面
  • 3分钟掌握nodeppt Mermaid插件:让你的演示文稿从此告别图片导入烦恼
  • 5分钟掌握dnd-kit网格对齐:React拖拽开发终极指南
  • 5分钟掌握WheelPicker:Android选择器的终极开发指南
  • ANTLR4 C++ 终极指南:从语法解析到高性能应用开发
  • 突破性音源!洛雪音乐实现全网音乐一键获取
  • BGP、OSPF、EIGRP,哪种协议用在哪?一文全讲透!
  • Google购物广告与自然产品列表如何1+1>2?3个被验证的流量协同策略
  • 写程序的时候必须做的一件事?听歌!!我精选粤语歌曲300首无损音乐,可以听十年了。
  • Vibe Coding 的终极委托:当机器拥有自主规划权,人类的“意图纯粹性”何在?
  • 漫画翻译神器manga-image-translator:哪个版本最适合你?
  • SpringBoot中的命名与开发规范
  • Vue 3 + TypeScript 严格模式下的 Performance.now() 实践:构建高性能前端应用