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

为什么要有二级指针

提示:文章

文章目录

  • 前言
  • 一、背景
  • 二、
    • 2.1
    • 2.2
  • 总结

前言

前期疑问:
本文目标:


一、背景

之前一直疑问为什么要有二级指针,一直没有写这个帖子,今天整理了一下,收获颇丰

二、

2.1

// 增加对二级指针的使用

/** 这两天突然想到为什么要有二级指针,二级指针的作用是什么* 我自己能想到的原因是因为指针指向内存可以访问内存。但是指针想改变内存中数据,就需要使用二级指针。* 然后基于上述的想法,我就写了下面的demo,但是实际情况和我想的不一样。* 我就想起来之前牛客题目涉及到的一个二级指针的题目,即没有使用二级指针的时候,没办法访问到指向的数据* 2024年8月16日14:28:31今天把牛客题目找了出来,看了下才恍然大悟* 今天这边两三天断断续续的内容整理起来*///下面是验证一级指针指向内存中数据,能访问但是不能改变数据的情况。
//#include <cstdio>
using namespace std;void testDiliverPointer(int *array)
{printf("array:%p\n", array);for (int i = 0; i < 6; i++) {printf("diliverPointer: %d ", array[i]);}printf("\n");array[0] = 3;for (int i = 0; i < 6; i++) {printf("change: %d ", array[i]);}printf("\n");
}void testPoint()
{int array[] = {1, 2, 3, 4, 5, 6};for (int i = 0; i < 6; i++) {printf("%d ", array[i]);}printf("\n");int* p = array;*p = 2;for (int i = 0; i < 6; i++) {printf("%d ", array[i]);}printf("\n");printf("array:%p\n", array);testDiliverPointer(array);
}void testCharDiliverPointer(char* array)
{printf("%s\n", array);array[1] = 'a';
}void testCharPointer()
{char array[] = "hello";char array2[] = "world";testCharDiliverPointer(array);printf("%s\n", array);
}void swap_int(int a , int b)
{int temp = a;a = b;b = temp;
}void swap_str(char*a , char*b)
{char*temp = a;a = b;b = temp;
}int DiliverSecondaryPointer(void)
{int a = 10;int b = 5;char*str_a = "hello world";char*str_b = "world hello";swap_int(a , b);swap_str(str_a , str_b);printf("%d %d %s %s\n",a,b,str_a,str_b);return 0;
}void DiliverParam(int param)
{printf("diliverParam addr:%p\n", &param);
}void DiliverParamPointer(int* paramPointer)
{printf("diliverParam pointer addr:%p\n", paramPointer);
}void Paramtest()
{int param = 0;printf("addr:%p\n", &param);DiliverParam(param);DiliverParamPointer(&param);
}int main()
{testPoint();//打印信息/** 1 2 3 4 5 6* 2 2 3 4 5 6* array:000000ca8cfffb90* array:000000ca8cfffb90* diliverPointer: 2 diliverPointer: 2 diliverPointer: 3 diliverPointer: 4 diliverPointer: 5 diliverPointer: 6* change: 3 change: 2 change: 3 change: 4 change: 5 change: 6*/// 从上述打印信息来看,// 第一次使用指针指向数组,再对数组成员指针解引用赋值,改变数组的值,可以通过指针更改变量的值// 第二次将数组指针传参,数组名弱化为指针。对指针解引用,更改指向的内存数据,可以实现。指针作为参数时,是进行拷贝的。但是因为指针是地址常量。拷贝后还是这个值。依然可以指向指向的内存// (这里我突然想到,参数为array,那这个array是个拷贝了实参数组地址的副本。这边的形参array的值改变了。但是拷贝的值是一样的。依然可以指向对应的内存)// (但是我打印的实参和形参的地址值是一样的啊,奇怪了),下面要验证一下这个形参地址和实参 地址一不一样?// 没有看到预期的结果。即没有传二级指针指针就不能更改参数的值。甚至我怀疑是不是只有在字符串中才存在这种情况?我又写了字符串来验证。testCharPointer();// 打印结果如下/** hello* hallo*/// 根据打印结果,字符串传参一级指针也可以更改字符串数据。我没有重现之前题目。就去找了题目。看了题目恍然大悟,知道之前的题目是怎么样的。下面是之前的题目DiliverSecondaryPointer();// 打印结果 10 5 hello world world hello// 然后我又仔细看了swap_str函数做的事情。又联想到之前问小鲁班为什么要有二级指针,回答是“当我们需要在函数中修改指针指向的内存地址时,我们需要传递指向指针的指针,即二级指针”// 上述的函数就是更改指针指向的地址// 所以应该就是这样,使用一级指针可以访问指针指向的内存。二级指针才能更改指针指向的内存。有点通透了啊//题外话,形参实参地址是否变化Paramtest();// 打印信息/** addr:0000009e581ffafc* diliverParam addr:0000009e581ffad0* diliverParam pointer addr:0000009e581ffafc*/// 根据打印信息,函数DiliverParam形参和实参的地址不一样。// DiliverParamPointer形参和实参的地址一样。这边我就懵逼了// 查了资料看到了一个很熟悉的名词,传参和传地址。又恍然大悟。// 事情还没完。当我在看传地址和‌传值的区别时在想。传地址是怎么实现只传了实参的地址。而没有进行形参对实参的地址值得拷贝。// 然后我又看了下代码。为什么Paramtest前后地址值是一样的。我发现了问题。就是我在Paramtest函数中,打印的是param的值。其实应该打印&param的地址。// 做完上面的判断我发现我的理解还是出了问题。那就是其实不是打印&param的值。实际情况是这样/** int *paramPointer = &param。即定义一个参数变量p指向变量param。所以打印p的值就是param的地址。但是实际上我使用的不是%p吗。* 想到这边我尝试写这样的代码printf("diliverParam pointer addr:%p\n", *paramPointer);这样也不对了,因为我不能打印变量的地址,要写成printf("diliverParam pointer addr:%p\n", &(*paramPointer));* 这不就是printf("diliverParam pointer addr:%p\n", paramPointer);吗,所以还是对的。所以原因是这样的。printf("diliverParam pointer addr:%p\n", paramPointer);打印就是实参param的地址。* 回到最初的问题,传地址是怎么实现值传递了实参的地址?是因为使用了一个指针指向实参的内存。然后使用这个指针形参可以访问内存。避免了拷贝。实际上当数据量比较大时,才有必要使用指针。* 所以在C语言中要避免大量拷贝数据,就要使用指针。当然在C++中有了更好的选择,即引用。引用可以避免空指针的情况出现。*/return 0;
}//上述的整理还是很通透的。

2.2

‌传地址和‌传值的区别主要体现在以下几个方面:

定义:
传值:将函数调用中‌实参的值复制一份给形参,形参和实参互不影响。在函数中修改形参的值不会影响实参的值。‌12
传址:将函数调用中实参的地址(指针)作为形参传递给函数,函数中修改形参的值会直接影响到实参的值。
内存使用:
传值:传递参数时会复制一份实参的值,形参会在函数内部重新分配内存空间,修改形参的值不会影响到实参的值,也不会影响到其他变量的值。‌2
传址:传递参数时只传递了实参的地址,形参并不会重新分配内存空间,修改形参的值会直接影响到实参的值,也会影响到实参指向的其他变量的值。
效率:
传值:传递参数时需要复制一份实参的值,如果实参的值较大,会造成比较大的开销,对于一些复杂的数据结构,如数组、结构体等,可能会导致程序运行效率较低。
传址:传递参数时只需要传递地址,对于较大的数据结构,可以避免复制大量的数据,从而提高程序运行效率。
通过例子进一步说明:

传值:就相当于克隆了一个同样的变量,操作的是克隆出来的那个,原来的变量没有变化。‌34
传址:直接对原来的变量进行操作,没有克隆新的变量

三、

3.1


总结

未完待续

相关文章:

为什么要有二级指针

提示&#xff1a;文章 文章目录 前言一、背景二、 2.1 2.2 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一、背景 之前一直疑问为什么要有二级指针&#xff0c;一直没有写这个帖子&#xff0c;今天整理了一下&#xff0c;收获颇丰 二、 2.1 // 增加对二级指针…...

如何保证数据不丢失?(死信队列)

死信队列 1、什么是死信 死信通常是消息在特定的场景下表现&#xff1a; 消息被拒绝访问消费者发生异常&#xff0c;超过重试次数消息的Expiration过期时长或者队列TTL过期时间消息队列到达最大容量 maxLength 2、什么是死信队列 只由死信构成的消息队列是死信队列 死信队…...

树莓派开发笔记01-树莓派的系统烧录以及初次开机配置

github主页&#xff1a;https://github.com/snqx-lqh gitee主页&#xff1a;https://gitee.com/snqx-lqh 本项目github地址&#xff1a;https://github.com/snqx-lqh/RaspberryPiLearningNotes 本项目gitee地址&#xff1a;https://gitee.com/snqx-lqh/RaspberryPiLearningNote…...

微信答题小程序产品研发-后端开发

在开发答题小程序的后端服务和数据库设计时&#xff0c;需要考虑API的设计、数据库模型的构建以及数据的安全性和一致性。 这里我采用了云开发&#xff0c;后端语言是Node&#xff0c;数据库是NoSql&#xff0c;然后我简单整理了各个功能模块的后端开发概要和数据库设计。 1. …...

回溯算法——LeetCode37 解数独

题目 力扣题目链接 思路 卡哥的思路&#xff0c;注意看他解释为什么是“二维回溯”。我的思路&#xff0c;类似y总解决 N 皇后问题时的第二种方法&#xff0c;即从左上到右下枚举棋盘的每个位置。 至于为什么与 N 皇后问题不一样&#xff0c;我认为是因为它每一行不止放一个…...

【CPP】继承语法详解与菱形继承

关于我&#xff1a; 睡觉待开机&#xff1a;个人主页 个人专栏: 《优选算法》《C语言》《CPP》 生活的理想&#xff0c;就是为了理想的生活! 作者留言 PDF版免费提供&#xff1a;倘若有需要&#xff0c;想拿我写的博客进行学习和交流&#xff0c;可以私信我将免费提供PDF版。…...

数据结构(6.2_1)——领接矩阵法

图的存储——邻接矩阵法 邻接矩阵&#xff08;Adjacency Matrix&#xff09;是一种使用二维数组来表示图的方法。在这种表示法中&#xff0c;矩阵的行和列都对应图的顶点。 特点 对于无向图&#xff0c;如果顶点i与顶点j之间有边&#xff0c;则矩阵的第i行第j列&#xff08;…...

诈骗未成功是否构成犯罪?

诈骗未成功不一定构成犯罪。在刑法上&#xff0c;构成诈骗罪需要满足特定的构成要件&#xff0c;包括有非法占有的目的、实施了虚构事实或隐瞒真相的行为、对方因此陷入错误认识并处分财产、行为人或第三方取得财产、被害人遭受财产损失。如果诈骗行为未能成功&#xff0c;即被…...

网络协议栈应用层的意义(内含思维导图和解析图通俗易懂超易理解)

绪论​&#xff1a; “节省时间的方法就是全力以赴的将所要做的事情完美快速的做完&#xff0c;不留返工重新学习的时间&#xff0c;才能省下时间给其他你认为重要的东西。” 本章主要讲到OSI网络协议栈中的应用层的作用和再次在应用层的角度理解协议的具体意义&#xff0c;以及…...

【NXP-MCXA153】i2c驱动移植

介绍 ‌I2C总线由飞利浦公司开发&#xff0c;是一种串行单工通信总线&#xff0c;它主要用于连接微控制器和其他外围设备并在总线上的器件之间传送信息&#xff08;需要指定设备地址&#xff09;&#xff1b;常见的i2c设备有EEPROM、触摸屏、各种IoT传感器、时钟模块等&#x…...

C++(11)类语法分析(2)

C(10)之类语法分析(2) Author: Once Day Date: 2024年8月17日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 源码分析_Once-Day的博客-CSDN博客 …...

数字验证每日十问--(3)

深拷贝和浅拷贝的区别&#xff1f; 当只拷贝对象中的成员变量和声明的句柄时&#xff0c;称为浅拷贝。浅拷贝只把对象中的句柄复制了&#xff0c;却没有复制句柄b所指向的对象。这会导致复制后&#xff0c;a2中的句柄b 和 a1 中的句柄b指向同一个对象&#xff0c;如果a2中的句…...

22.给定 n 对括号,实现一个算法生成所有可能的正确匹配的括号组合

22. Generate Parentheses 题目 给定 n 对括号,编写一个函数生成所有可能的正确匹配的括号组合。 例如,当 n = 3 时,可能的组合集合为: ["((()))","(()())","(())()","()(())","()()()" ]题目大意 给出 n 代表生成…...

检测到目标URL存在http host头攻击漏洞

漏洞描述 修复措施 方法一&#xff1a; nginx 的 default_server 指令可以定义默认的 server 去处理一些没有匹配到 server_name 的请求&#xff0c;如果没有显式定义&#xff0c;则会选取第一个定义的 server 作为 default_server。 server { …...

C++奇迹之旅:手写vector模拟实现与你探索vector 容器的核心机制与使用技巧

文章目录 &#x1f4dd;基本框架&#x1f320; 构造和销毁&#x1f309;vector()&#x1f309;vector(const vector& v)&#x1f309;vector(size_t n, const T& value T())&#x1f309;赋值拷贝构造&#xff1a;vector<T>& operator(vector<T> v)&a…...

018、钩子函数 mounted和beforeDestroy、父组件向子组件传递参数 props 的使用

文章目录 1、mounted 和 beforeDestroy1.1、mounted1.2、beforeDestroy 2、父组件向子组件传递参数 props2.1、子组件定义2.2、父组件调用子组件并传参 3、完整例子3.1、父组件 Tags.vue3.2、子组件 TagsMenu.vue3.3、效果图 1、mounted 和 beforeDestroy 1.1、mounted mount…...

xlnt在Windows中的dll,lib生成

前言 花了半天时间想要把xlnt 集成到VS2022 Cmake项目中,以我目前掌握的能力,Cmake语法对于我来说难懂,对于只是使用过Cmake编译MySQL,或是其他lib,dll库的小白来说,不应该为了显示自己能力多么出众,强行去配置一些程序内容。 生活中没有绝对的事情,有舍有得. https://github…...

【网络】私有IP和公网IP的转换——NAT技术

目录 引言 NAT工作机制​编辑 NAT技术的优缺点 优点 缺点 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 公网被子网掩码划分为层状结构&#xff0c;一个公网IP的机器又可以用很多私有IP搭建内网。在日常生活场景中用的都是私有IP&#xff0c;例如手机&#xff0c;…...

java 面试 PDF 资料整理

“尊贵的求知者&#xff0c;作者特此献上精心编纂的Java面试宝典PDF&#xff0c;这份资料凝聚了无数面试精华与实战经验&#xff0c;是通往Java技术殿堂的钥匙。若您渴望在Java编程的求职之路上稳健前行&#xff0c;只需轻轻一点&#xff0c;完成这象征支持与认可的一键三联&am…...

初步认识Linux系统

前言 Linux系统具有许多优点&#xff0c;不仅系统性能稳定&#xff0c;而且是开源软件。其核心防火墙组件性能高效、配置简单&#xff0c;保证了系统的安全。在很多企业网络中&#xff0c;为了追求速度和安全&#xff0c;Linux不仅仅是被网络运维人员当作服务器使用&#xff0c…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...