掌握Go语言:探索Go语言指针,解锁高效内存操作与动态数据结构的奥秘(19)
指针是一个变量,它存储了另一个变量的地址。在Go语言中,指针提供了直接访问内存地址的能力,允许程序直接操作内存,这在某些场景下非常有用。
Go语言指针的详细使用方法
声明指针
可以使用*符号来声明指针变量,例如:
var ptr *int // 声明一个整型指针
获取变量地址
使用&操作符可以获取变量的地址,例如:
var num int = 10
ptr := &num // 将num的地址赋给ptr
访问指针指向的值
使用*操作符可以获取指针指向的值,例如:
fmt.Println(*ptr) // 输出:10,即指针ptr所指向的变量num的值
修改指针指向的值
可以通过指针修改所指向变量的值,例如:
*ptr = 20
fmt.Println(num) // 输出:20,因为通过ptr修改了num的值
Go语言指针的使用示例
package mainimport "fmt"func main() {var num int = 10var ptr *int // 声明一个整型指针ptr = &num // 将num的地址赋给ptrfmt.Println("Value of num:", num)fmt.Println("Address of num:", ptr)fmt.Println("Value at address stored in ptr:", *ptr)*ptr = 20 // 修改ptr所指向的值fmt.Println("New value of num:", num)
}
以上代码演示了Go语言中指针的基本用法,包括声明指针、获取变量地址、访问指针指向的值以及修改指针指向的值等操作。
-
var num int = 10:声明一个整型变量num并初始化为10。 -
var ptr *int:声明一个整型指针ptr,但未初始化,此时ptr被赋值为nil。 -
ptr = &num:将变量num的地址赋给指针ptr,使其指向变量num的内存地址。 -
fmt.Println("Value of num:", num):输出变量num的值,即10。 -
fmt.Println("Address of num:", ptr):输出变量num的地址,即指针ptr的值。 -
fmt.Println("Value at address stored in ptr:", *ptr):通过指针ptr访问其指向的值,即变量num的值,输出10。 -
*ptr = 20:修改指针ptr所指向的值,即修改变量num的值为20。 -
fmt.Println("New value of num:", num):输出修改后的变量num的值,即20。
通过上述步骤,可以清晰地理解指针的基本使用方法:获取变量地址、访问指针指向的值以及修改指针指向的值。指针在Go语言中是一种重要的数据类型,能够有效地处理内存地址和数据交换,但也需要小心使用以避免指针相关的问题。
Go语言指针的应用场景
1. 传递函数参数
通过传递指针作为函数参数,可以在函数内部修改外部变量的值,避免函数参数的拷贝。这种方式可以有效地减少内存消耗,并且能够在函数内部对外部变量进行修改,达到更灵活的控制效果。
详解: 当函数参数以值传递方式传递时,会将参数的副本传递给函数,因此在函数内部对参数的修改不会影响到外部变量的值。而使用指针作为函数参数,则直接传递了变量的内存地址,函数内部对指针指向的内存进行修改,从而改变了外部变量的值。
示例:
package mainimport "fmt"func modifyValue(ptr *int) {*ptr = 100 // 修改指针指向的变量的值
}func main() {var num int = 10fmt.Println("Before:", num) // 输出:Before: 10modifyValue(&num) // 将num的地址传递给函数fmt.Println("After:", num) // 输出:After: 100,外部变量被修改了
}
2. 动态内存分配
使用指针可以在运行时动态分配内存,从而实现灵活的数据结构。在需要根据程序运行时的条件动态分配内存的情况下,指针可以提供更灵活的内存管理方式,避免静态分配带来的内存浪费或不足。
详解: 通过new关键字或make函数可以在运行时动态分配内存,返回的是指向新分配内存的指针。这使得我们可以根据程序运行时的需要动态创建变量或数据结构,提高程序的灵活性和性能。
示例:
package mainimport "fmt"func main() {ptr := new(int) // 使用new关键字动态分配一个整型变量的内存*ptr = 10fmt.Println("Value:", *ptr) // 输出:Value: 10
}
3. 访问底层硬件
在与底层硬件交互时,指针可以直接操作内存地址,提高程序的效率。通过指针直接读写内存,可以避免额外的内存拷贝操作,从而加速数据访问和处理过程。
详解: 访问底层硬件时,常常需要直接读写内存地址来与硬件进行通信。指针可以直接操作内存地址,因此在这种场景下,使用指针可以提高程序的效率和性能。
示例:(简单示例,实际场景会更复杂)
package mainimport "unsafe"func main() {var data int32 = 42addr := unsafe.Pointer(&data) // 获取data的内存地址// 访问底层硬件,写入数据hardwareWrite(addr, 100)// 从底层硬件读取数据result := hardwareRead(addr)println(result) // 输出:100
}// 模拟底层硬件写入数据的函数
func hardwareWrite(addr unsafe.Pointer, value int32) {// 实际操作...
}// 模拟底层硬件读取数据的函数
func hardwareRead(addr unsafe.Pointer) int32 {// 实际操作...return 100
}
通过上述示例,我们可以看到指针在访问底层硬件时的应用,通过直接操作内存地址,可以实现与硬件的高效交互。
进销存实例
以下是一个简单的指针进销存实例,用于管理产品的库存量和销售记录:
package mainimport "fmt"// Product 结构体表示产品信息
type Product struct {ID intName stringStock int // 库存量Price float64
}// 函数用于更新产品的库存量
func updateStock(product *Product, quantity int) {product.Stock += quantity
}// 函数用于记录产品的销售记录
func recordSale(product *Product, quantity int) {if product.Stock >= quantity {product.Stock -= quantityfmt.Printf("Sale recorded: %dx %s\n", quantity, product.Name)} else {fmt.Println("Insufficient stock to record sale.")}
}func main() {// 初始化产品信息iphone := Product{ID: 1, Name: "iPhone 12", Stock: 100, Price: 999.99}// 显示初始库存量fmt.Printf("Initial stock of %s: %d\n", iphone.Name, iphone.Stock)// 更新库存量updateStock(&iphone, 50)fmt.Printf("Stock after adding 50 %s: %d\n", iphone.Name, iphone.Stock)// 记录销售记录recordSale(&iphone, 30)// 显示更新后的库存量fmt.Printf("Final stock of %s: %d\n", iphone.Name, iphone.Stock)
}
详解:
-
Product 结构体:定义了产品的结构体,包含了产品的ID、名称、库存量和价格等信息。
-
updateStock 函数:接受一个指向 Product 结构体的指针和一个整数参数,用于更新产品的库存量。通过指针传递,可以直接修改产品的库存量,而无需进行值传递。
-
recordSale 函数:接受一个指向 Product 结构体的指针和一个整数参数,用于记录产品的销售记录。如果产品的库存量足够,就会记录销售记录并更新库存量;否则,会提示库存不足无法销售。
-
主函数 main:初始化了一个名为 iPhone 12 的产品,显示了初始的库存量。然后调用了 updateStock 函数来增加 iPhone 12 的库存量,并调用 recordSale 函数记录了一次销售记录。最后,显示了更新后的库存量。
在这个例子中,通过使用指针作为函数参数,可以直接修改产品的库存量和记录销售记录,而无需进行复制和返回操作。这样可以提高程序的效率,并且更直观地表达了对产品数据的修改。
Go语言指针的注意事项
1. 空指针
空指针是指在声明时未初始化的指针,会被默认赋值为nil。如果在使用空指针时不进行有效的空指针判断,可能会导致程序崩溃或出现意外行为。
详解: 空指针在未经初始化时被默认赋值为nil,表示该指针不指向任何有效的内存地址。如果在使用空指针时尝试解引用或调用指针指向的方法,会触发空指针异常,导致程序崩溃。
示例:
package mainimport "fmt"func main() {var ptr *intfmt.Println(*ptr) // 尝试解引用空指针,会导致panic
}
在上述示例中,指针ptr未经初始化,因此被赋值为nil。尝试解引用空指针会导致panic。
2. 指针算术运算
Go语言不支持指针的算术运算,如ptr++等操作。因为指针的加减运算可能会导致内存越界或不可预期的行为,因此在Go语言中不允许进行指针的算术运算。
3. 指针逃逸
当指针逃逸到堆上分配内存时,需要注意内存泄漏的风险,及时释放不再使用的内存。如果忽略了指针逃逸导致的内存泄漏问题,会导致程序消耗过多的内存资源,影响系统的稳定性和性能。
4. 野指针
野指针是指针指向的内存可能已经被释放,但指针仍然保留着地址。使用野指针会导致未定义的行为,可能会读取到无效的数据,或者修改已经被释放的内存,从而导致程序崩溃或数据损坏。
示例:
package mainimport "fmt"func main() {var ptr *intvar num int = 10ptr = &numfmt.Println(*ptr) // 输出:10// 假设在这之后释放了num所在的内存,ptr成为野指针// 此时再次访问*ptr会导致未定义的行为fmt.Println(*ptr) // 未定义的行为
}
在上述示例中,ptr最初指向变量num的内存地址,但后续可能释放了num所在的内存,此时ptr成为野指针。再次访问*ptr会导致未定义的行为。
通过理解和遵守上述指针的注意事项,可以有效地避免指针相关的错误和问题,确保程序的稳定性和可靠性。
总结
指针在Go语言中具有重要的作用,它们不仅可以用于传递函数参数、动态内存分配,还可以在与底层硬件交互时提高程序的效率。然而,在使用指针时需要注意避免空指针和野指针的问题,以及合理管理内存。通过深入理解指针的原理和使用方法,可以更好地应用指针来提高程序的性能和灵活性。
相关文章:
掌握Go语言:探索Go语言指针,解锁高效内存操作与动态数据结构的奥秘(19)
指针是一个变量,它存储了另一个变量的地址。在Go语言中,指针提供了直接访问内存地址的能力,允许程序直接操作内存,这在某些场景下非常有用。 Go语言指针的详细使用方法 声明指针 可以使用*符号来声明指针变量,例如&…...
大数据面试题 —— Zookeeper
目录 ZooKeeper 的定义ZooKeeper 的特点ZooKeeper 的应用场景你觉得Zookeeper比较重要的功能ZooKeeper 的选举机制 ***zookeeper主节点故障,如何重新选举?ZooKeeper 的监听原理 ***zookeeper集群的节点数为什么建议奇数台 ***ZooKeeper 的部署方式有哪几…...
【安全类书籍-6】僵尸网络:网络程序杀手
目录 内容 用处 下载链接 内容 这本书着重探讨以下几个主题: 1. 僵尸网络基础:介绍僵尸网络的基本构成、运作机制以及在全球网络空间中的影响和威胁程度。 2. 僵尸网络技术剖析:详细分析僵尸网络的组件,如命令控制中心(C&C)、恶意软件传播途径、感染节点的招募和…...
文件的创建与删除
文件的创建 使用File类创建一个文件对象,例如:File filenew File("c:\\myletter" , "letter.txt"); public boolean createNewFile();/*如果c:\myletter目录中没 有名字为letter.txt文件,文件对象file调用createNewFil…...
图论题目集一(代码 注解)
目录 题目一: 题目二: 题目三: 题目四: 题目五: 题目六: 题目七: 题目一: #include<iostream> #include<queue> #include<cstring> using namespace st…...
解释MVC和MVVM架构模式
一、解释MVC和MVVM架构模式 MVC和MVVM都是常见的前端架构模式,用于抽象分离并解决特定问题。这两种模式在结构上具有一定的相似性,但在细节和数据处理方式上存在一些差异。 MVC,即Model-View-Controller,是一种用于应用程序分层…...
OLLAMA:如何像云端一样运行本地大语言模型
简介:揭开 OLLAMA 本地大语言模型的神秘面纱 您是否曾发现自己被云端语言模型的网络所缠绕,渴望获得更本地化、更具成本效益的解决方案?那么,您的探索到此结束。欢迎来到 OLLAMA 的世界,这个平台将彻底改变我们与大型…...
React全家桶及原理解析-lesson4-Redux
lesson4-react全家桶及原理解析.mov React全家桶及原理解析 React全家桶及原理解析 课堂⽬标资源起步Reducer 什么是reducer什么是reduceRedux 上⼿ 安装reduxredux上⼿检查点react-redux 异步代码抽取Redux拓展 redux原理 核⼼实现中间件实现redux-thunk原理react-redux原理 实…...
电商api数据接口技术开发来赞达lazada通过商品ID抓取商品详情信息item_get请求key接入演示
要获取Lazada的商品详情,你需要使用item_get请求。首先,你需要注册一个开发者账号并获取API密钥(App Key和App Secret)。然后,你可以使用以下Python代码示例来获取商品详情: # coding:utf-8 ""&…...
零基础入门多媒体音频(2)-音频焦点2
说实话,android的代码是越来越难以阅读。业务函数里面狗皮膏药似的补丁与日俱增。继上篇简要介绍音频焦点的文章,这篇文章的主要内容是分析audiofocus的实现。看了一下午的相关代码都没找到做audiofocus策略的核心逻辑。目前能看懂的大概包含下面两个逻辑…...
Spark杂谈
文章目录 什么是Spark对比HadoopSpark应用场景Spark数据处理流程什么是RDDSpark架构相关进程入门案例:统计单词数量Spark开启historyServer 什么是Spark Spark是一个用于大规模数据处理的统一计算引擎Spark一个重要的特性就是基于内存计算,从而它的速度…...
【PyTorch】进阶学习:一文详细介绍 torch.save() 的应用场景、实战代码示例
【PyTorch】进阶学习:一文详细介绍 torch.save() 的应用场景、实战代码示例 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程…...
私域流量运营的关键要素和基本步骤
解锁增长的四大关键: 关键要素一:精准营销 精准营销是私域流量运营的核心所在。通过精细化运营和个性化服务,企业可以将普通用户转化为忠实粉丝,提高用户的粘性和转化率。采用数据驱动的精准营销策略,深度挖掘用户需求…...
k8s部署hadoop
(作者:陈玓玏) 配置和模板参考helm仓库:https://artifacthub.io/packages/helm/apache-hadoop-helm/hadoop 先通过以下命令生成yaml文件: helm template hadoop pfisterer-hadoop/hadoop > hadoop.yaml用kube…...
deepspeed分布式训练在pytorch 扩展(PyTorch extensions)卡住
错误展示: Using /root/.cache/torch_extensions/py310_cu121 as PyTorch extensions root... Using /root/.cache/torch_extensions/py310_cu121 as PyTorch extensions root... 错误表现: 出现在多卡训练过程的pytorch 扩展,deepspee…...
Rust 的 HashMap
在 Rust 中,HashMap 是一个从键(key)映射到值(value)的数据结构。它允许你以 O(1) 的平均时间复杂度存储、检索和删除键值对。HashMap 实现了 std::collections::HashMap 结构体,通常通过 use std::collect…...
exporter方式监控达梦数据库
蓝鲸监控 随着国产化和信创的深入,开始普遍使用国产化数据库–如达梦数据库,蓝鲸平台默认没有对其进行监控,但是平台了提供监控告警的能力。比如脚本采集,脚本的是一种灵活和快速的监控采集方式,不同层的监控对象都可…...
供应链安全之被忽略的软件质量管理平台安全
背景 随着我国信息化进程加速,网络安全问题更加凸显。关键信息基础设施和企业单位在满足等保合规的基础上,如何提升网络安全防御能力,降低安全事件发生概率?默安玄甲实验室针对SonarQube供应链安全事件进行分析,强调供…...
python入门(二)
python的安装很方便,我们这里就不再进行讲解,大家可以自己去搜索视频。下面分享一下Python的入门知识点。 执行命令的方式 在安装好python后,有两种方式可以执行命令: 命令行程序文件,后缀名为.py 对于命令行&…...
Mysql,MongoDB,Redis的横纵向对比
一,什么是Mysql Mysql是一款安全,可以跨平台,高效率的数据库系统,运行速度高,安全性能高,支持面向对象,安全性高,并且成本比较低,支持各种开发语言,数据库的存储容量大,有许多的内置函数。 二,什么是MongoDB MongoDB是基于分布式文件存储的数据库,是一个介于关…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
