news 2026/1/17 6:08:20

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进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/23 14:06:19

GitHub Desktop完整中文界面解决方案:三步实现完美本地化体验

GitHub Desktop完整中文界面解决方案:三步实现完美本地化体验 【免费下载链接】GitHubDesktop2Chinese GithubDesktop语言本地化(汉化)工具 项目地址: https://gitcode.com/gh_mirrors/gi/GitHubDesktop2Chinese 还在为GitHub Desktop的英文界面而困扰吗&…

作者头像 李华
网站建设 2026/1/12 20:42:58

5分钟快速上手:uni-app插件市场完整使用指南

5分钟快速上手:uni-app插件市场完整使用指南 【免费下载链接】uni-app A cross-platform framework using Vue.js 项目地址: https://gitcode.com/dcloud/uni-app uni-app插件市场是DCloud官方推出的跨端开发组件生态平台,汇聚了数千款高质量组件…

作者头像 李华
网站建设 2025/12/22 12:54:44

Dify与Spring AI集成难题一网打尽,资深架构师亲授生产级解决方案

第一章:Dify与Spring AI集成概述Dify 作为一款面向 AI 应用开发的低代码平台,提供了可视化编排、模型管理与 API 服务发布能力。Spring AI 是 Spring 生态中用于简化人工智能应用开发的框架,支持与主流大模型平台对接。将 Dify 与 Spring AI …

作者头像 李华
网站建设 2025/12/22 10:20:59

学习笔记——Makefile

基本概念 Makefile 是工程管理工具,用于编译多个源文件(可能在不同目录下),可以添加编译选项。 基本语法规则 makefile 目标: 依赖 [TAB] 规则命令 版本演进 版本1:直接编译 makefile a.out: main.c func.cgcc…

作者头像 李华
网站建设 2025/12/23 1:28:56

【必看收藏】2026大模型校招趋势:5.2W月薪岗位揭秘,AI人才就业指南

2026年AI人才校招市场呈现显著扩张趋势,大模型算法岗位月薪可达5.2万,顶尖人才薪资翻倍。高科技企业(60%)比金融行业(40.1%)更重视AI人才,近六成企业计划扩招。企业更看重数学与算法基础(60.3%)和项目实践(52.5%),名校学历重要性下…

作者头像 李华