golang指针

news2025/3/10 15:05:19

指针

区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。

要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值。

1.1. Go语言中的指针

Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)和*(根据地址取值)。

1.1.1. 指针地址和指针类型

每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用&字符放在变量前面对变量进行“取地址”操作。 Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int、*int64、*string等。

取变量指针的语法如下:

    ptr := &v    // v的类型为T

其中:

    v:代表被取地址的变量,类型为T
    ptr:用于接收地址的变量,ptr的类型就为*T,称做T的指针类型。*代表指针。

举个例子:

func main() {
    a := 10
    b := &a
    fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
    fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
    fmt.Println(&b)                    // 0xc00000e018}

我们来看一下b := &a的图示:

1.1.2. 指针取值

在对普通变量使用&操作符取地址后会获得这个变量的指针,然后可以对指针使用*操作,也就是指针取值,代码如下。

func main() {
    //指针取值
    a := 10
    b := &a // 取变量a的地址,将指针保存到b中
    fmt.Printf("type of b:%T\n", b)
    c := *b // 指针取值(根据指针去内存取值)
    fmt.Printf("type of c:%T\n", c)
    fmt.Printf("value of c:%v\n", c)}

输出如下:

    type of b:*int
    type of c:int
    value of c:10

总结: 取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。

变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:\

    1.对变量进行取地址(&)操作,可以获得这个变量的指针变量。
    2.指针变量的值是指针地址。
    3.对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。

指针传值示例:

func modify1(x int) {
    x = 100}func modify2(x *int) {
    *x = 100}func main() {
    a := 10
    modify1(a)
    fmt.Println(a) // 10
    modify2(&a)
    fmt.Println(a) // 100}

1.1.3. 空指针

  • 当一个指针被定义后没有分配到任何变量时,它的值为 nil

  • 空指针的判断

package mainimport "fmt"func main() {
    var p *string
    fmt.Println(p)
    fmt.Printf("p的值是%v\n", p)
    if p != nil {
        fmt.Println("非空")
    } else {
        fmt.Println("空值")
    }}

1.1.4. new和make

我们先来看一个例子:

func main() {
    var a *int
    *a = 100
    fmt.Println(*a)

    var b map[string]int
    b["测试"] = 100
    fmt.Println(b)}

执行上面的代码会引发panic,为什么呢? 在Go语言中对于引用类型的变量,我们在使用的时候不仅要声明它,还要为它分配内存空间,否则我们的值就没办法存储。而对于值类型的声明不需要分配内存空间,是因为它们在声明的时候已经默认分配好了内存空间。要分配内存,就引出来今天的new和make。 Go语言中new和make是内建的两个函数,主要用来分配内存

1.1.5. new

new是一个内置的函数,它的函数签名如下:

    func new(Type) *Type

其中,

    1.Type表示类型,new函数只接受一个参数,这个参数是一个类型
    2.*Type表示类型指针,new函数返回一个指向该类型内存地址的指针。

new函数不太常用,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。举个例子:

func main() {
    a := new(int)
    b := new(bool)
    fmt.Printf("%T\n", a) // *int
    fmt.Printf("%T\n", b) // *bool
    fmt.Println(*a)       // 0
    fmt.Println(*b)       // false}

本节开始的示例代码中var a *int只是声明了一个指针变量a但是没有初始化,指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。应该按照如下方式使用内置的new函数对a进行初始化之后就可以正常对其赋值了:

func main() {
    var a *int
    a = new(int)
    *a = 10
    fmt.Println(*a)}

1.1.6. make

make也是用于内存分配的,区别于new,它只用于slice、map以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。make函数的函数签名如下:

func make(t Type, size ...IntegerType) Type

make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作。这个我们在上一章中都有说明,关于channel我们会在后续的章节详细说明。

本节开始的示例中var b map[string]int只是声明变量b是一个map类型的变量,需要像下面的示例代码一样使用make函数进行初始化操作之后,才能对其进行键值对赋值:

func main() {
    var b map[string]int
    b = make(map[string]int, 10)
    b["测试"] = 100
    fmt.Println(b)}

1.1.7. new与make的区别

    1.二者都是用来做内存分配的。
    2.make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
    3.而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。

1.1.8. 指针小练习

  • 程序定义一个int变量num的地址并打印

  • 将num的地址赋给指针ptr,并通过ptr去修改num的值

package mainimport "fmt"func main() {
    var a int
    fmt.Println(&a)
    var p *int
    p = &a    *p = 20
    fmt.Println(a)}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/116899.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux中如何理解线程?线程ID到底是什么?

朋友们好,这里简要介绍了进程和线程的区别以及对LINUX中线程ID的理解,本人目前理解尚浅,若文中有表述不当的地方还望理解并指正,谢谢大家! 文章目录一:进程和线程二:线程ID和进程地址空间布局一…

5 项目部署

5.1 Linux-项目部署 5.1.1 环境 5.1.1.1 开发环境(dev) 外部用户无法访问,开发人员使用,版本变动很大 平时大家大多是在Windows或者Mac操作系统下去编写代码进行开发. 在开发环境中安装大量的软件,这样会导致环境的稳…

2022 年度盘点 | 更成熟的 AI,更破圈的技术狂欢

By 超神经内容一览:2022 年 AI 领域发展不断提速,新技术成果纷纷落地,模型迭代加速升级。本文总结了 2022 年 AI 领域各大公司的技术成就。关键词:年终盘点 大厂 技术创新2022 年在此起彼伏的咳嗽声中接近尾声,这一…

onCreate、onSaveInstanceState、onRestoreInstance一个参数和两个参数

Android Studio移动应用开发——onCreate、onSaveInstanceState、onRestoreInstance一个参数和两个参数_dear_jing的博客-程序员宅基地 - 程序员宅基地 在做Android生命周期实验过程中,把 Log.i(TAG, "(1) onCreate()") 写到了含有两个参数的函数 onSave…

HTML5 元素拖放

文章目录HTML5 元素拖放概述触发事件实现元素拖放功能dataTransfer元素拖动效果垃圾箱效果HTML5 元素拖放 概述 在HTML5中,我们只需要给元素添加一个draggable属性,然后设置该属性值为true,就能实现元素的拖放。 拖放,指的是“…

【Python】Numpy分布函数总结

文章目录总表均匀分布和三角分布幂分布与正态分布相关的分布与Gamma相关的分布极值分布总表 np.random中提供了一系列的分布函数,用以生成符合某种分布的随机数。下表中,如未作特殊说明,均有一个size参数,用以描述生成数组的尺寸…

【综合笔试题】难度 1.5/5,常规二叉树爆搜题

题目描述 这是 LeetCode 上的 95. 不同的二叉搜索树 II ,难度为 中等。 Tag : 「树」、「二叉搜索树」、「BST」、「DFS」、「递归」、「爆搜」 给你一个整数 n,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以…

2022出圈的ML研究:爆火的Stable Diffusion、通才智能体Gato,LeCun转推

这些机器学习领域的研究你都读过吗? 2022 年即将步入尾声。在这一年里,机器学习领域涌现出了大量有价值的论文,对机器学习社区产生了深远的影响。 今日,ML & NLP 研究者、Meta AI 技术产品营销经理、DAIR.AI 创始人 Elvis S.…

CSRF漏洞渗透与攻防(一)

目录 前言 什么是CSRF漏洞 CSRF实现流程 CSRF漏洞危害 XSS漏洞危害 CSRF与XSS区别 CSRF分类 GET型: POST型: CSRF漏洞案列模拟 CSRF常用Payload: CSRF漏洞挖掘 检测工具 CSRF漏洞防御 防御思路 我们该如何去防御CSRF漏洞…

LeetCode动态规划—打家劫舍从平板板到转圈圈(198、213)

打家劫舍平板板打家劫舍转圈圈打家劫舍(进阶版)平板板打家劫舍 转化子问题: 按顺序偷n间房子,就是考虑偷前n-1间房子还是偷前n-2间房子再偷第n间房子。 列出公式: res[n] max{ res[n-1] , 数组中最后一个数据res[n-…

企业信息化之源代码防泄密场景分析

场景描述 随着企业信息化发展迅速,越来越多的无形资产面临着被泄露,被盗取的,或员工无意导致的数据泄密风险。尤其是有源码开发的企业,源代码的安全更是重中之重,一旦泄密,有可能给企业带来不可估量的损失…

全程数字化的企业电子招标采购管理系统源码

全程数字化的采购管理 智能化平台化电子化内外协同 明理满足采购业务全程数字化, 实现供应商管理、采购需求、全网寻源、全网比价、电子招 投标、合同订单执行的全过程管理。 传统采购模式面临的挑战 如何以最合适的价格,找到最优的供应商,购买到最好的产品和服务?…

程序员必备网站,建议收藏!

俗话说的好,一个程序员,20%靠知识储备,80%靠网络搜索。 打开代码,打开Google,开始工作。 那么常用的写码软件,你知道几个呢? 下面我们来一起看一下常用的写码软件吧~ 建议收藏本文&#xff…

【算法】面试题 - 链表

链表相关面试题141. 环形链表问题:快慢指针为什么一定会相遇142. 环形链表 II问题:如何确认入口160. 相交链表237. 删除链表中的节点19. 删除链表的倒数第 N 个结点21. 合并两个有序链表23. 合并K个升序链表(两种解法)扩展&#x…

国产手机扬眉吐气,终于打击了苹果的嚣张气焰

苹果在9月份、10月份都取得了快速增长,而国产手机品牌持续下滑,但是11月份终于让国产手机捡回了主动权,11月份的数据显示有国产手机品牌的出货量大幅增长,而苹果的出货量却大幅下滑,国产手机成功反击了苹果。分析机构给…

Vue + SpreadJS 实现高性能数据展示与分析

Vue SpreadJS 实现高性能数据展示与分析 在前端开发领域,表格一直都是一个高频使用的组件,尤其是在中后台和数据分析场景下。但当一屏展示数据超过1000条数据记录时,会出现浏览器卡顿等问题,严重影响客户体验。为解决这些性能问…

Seay代码审计系统审计实战

今天继续给大家介绍渗透测试相关知识,本文主要内容是Seay代码审计系统审计实战。 免责声明: 本文所介绍的内容仅做学习交流使用,严禁利用文中技术进行非法行为,否则造成一切严重后果自负! 再次强调:严禁对未…

【算法题解】5. 删除有序数组中的重复项 + 移动零

文章目录删除有序数组中的重复项题目解题思路代码实现复杂度分析移动零题目解题思路代码实现复杂度分析删除有序数组中的重复项 题目 给你一个 升序排列 的数组 nums ,请你原地删除重复出现的元素,使每个元素只出现一次 ,返回删除后数组的新…

Python 并发编程实战,用多线程、多进程、多协程加速程序运行

Python 并发编程实战,用多线程、多进程、多协程加速程序运行 文章目录Python 并发编程实战,用多线程、多进程、多协程加速程序运行1、什么是CPU密集型计算、IO密集型计算?2、多线程、多进程、多协程的对比3、怎么根据任务选择对应技术&#x…

达梦数据成功过会!信创浪潮中如何成就一家国产龙头?

‍‍数据智能产业创新服务媒体——聚焦数智 改变商业2022年12月22日,上海证券交易所科创板上市委员会发布《2022年第110次审议会议结果公告》,武汉达梦数据股份有限公司(首发)符合发行条件、上市条件和信息披露要求。该公告标志着…