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

深入理解指针(2)

1.const修饰指针

加上const后就修改不了了

const 使得a具有了常属性,所以a就不能被修改了

但是注意a本质上还是变量,不是常量,是常变量。

但在C++中const修饰的变量就是常量

但是如果我们绕过a,使⽤a的地址,去修改a就能做到了,虽然这样做是在打破语法规则。

我们可以看到这⾥⼀个确实修改了,但是我们还是要思考⼀下,为什么n要被const修饰呢?就是为了 不能被修改,如果p拿到n的地址就能修改n,这样就打破了const的限制,这是不合理的,所以应该让 p拿到n的地址也不能修改n,那接下来怎么做呢? 

//const修饰指针变量时放在*的右侧。其限制的是指针变量p本身,指针变量不可以再指向其他变量,但是可以通过指针变量,修改指针变量所指向的内容。 

对于这段代码

由此我们可以得到以下信息:

1.p中可以存放一个地址

2.*p—>a—>10

3.&p—>0x0012ff48

我们继续运行代码: 

由此可见:

const修饰指针变量时,放在*左边,限制的是:指针指向的内容,不能通过指针来修改所指向的内容。但是可以修改指针变量本身的值(修改的指针变量的指向)

结论:const修饰指针变量的时候

• const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变。

• const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变。

2.指针运算

(指针的作用就是访问内存的!)

1.指针+-整数

指针+1

int a = 10;

int* p = &a;

p + 1 --->跳过4个字节

         --->1*sizeof(int)

____________________________

type* p = &a;

p + 1 --->跳过4个字节

         --->1*sizeof(type)

_____________________________

type* p = &a;

p + n --->跳过4个字节

         --->n*sizeof(type)

因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸⽠就能找到后⾯的所有元素。

用指针方式打印:

//p+i 这⾥就是指针+整数

2.指针-指针

日期+天数

日期-天数

指针+整数

——————————————————

日期-日期 —— 中间的天数

指针-指针 —— 得到的是两个指针的元素个数

——————————————————

日期 + 日期 = ???没有这个操作

指针 + 指针 = ???也没有该操作

——————————————————

指针 - 指针计算的前提条件是:两个指针指向了同一块空间!

所以:

|指针 - 指针| = 两个指针之间元素的个数

将代码进行改写:

再继续改写: 

3.指针的关系运算

指针和指针比较大小

地址和地址比较大小

3.野指针

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。

野指针成因:

1.指针未初始化

2.指针越界访问

3. 指针指向的空间释放

4.如何规避野指针

1.指针初始化

明确知道指针应该指向哪里,就给初始化一个明确的地址

如果现在还不知道应该指向哪里,那就初始化NULL 

上图中可以看出:

在C语言内存中只有一部分是给用户程序的

2.小心指针越界

⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是 越界访问。

3.指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性

当指针变量指向⼀块区域的时候,我们可以通过指针访问该区域,后期不再使⽤这个指针访问空间的 时候,我们可以把该指针置为NULL。因为约定俗成的⼀个规则就是:只要是NULL指针就不去访问, 同时使⽤指针之前可以判断指针是否为NULL。

我们可以把野指针想象成野狗,野狗放任不管是⾮常危险的,所以我们可以找⼀棵树把野狗拴起来, 就相对安全了,给指针变量及时赋值为NULL,其实就类似把野狗栓前来,就是把野指针暂时管理起来。

不过野狗即使拴起来我们也要绕着⾛,不能去挑逗野狗,有点危险;对于指针也是,在使⽤之前,我 们也要判断是否为NULL,看看是不是被拴起来起来的野狗,如果是不能直接使⽤,如果不是我们再去使⽤。

4.避免返回局部变量的地址

如造成野指针的第3个例⼦,不要返回局部变量的地址。

5.assert断⾔

上⾯代码在程序运⾏到这⼀⾏语句时,验证变量p 是否等于 NULL 。如果确实不等于 NULL ,程序继续运⾏,否则就会终⽌运⾏,并且给出报错信息提⽰。

assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值⾮零),assert() 不会产⽣任何作⽤,程序继续运⾏。如果该表达式为假(返回值为零),assert() 就会报错,在标准错误流 stderr 中写⼊⼀条错误信息,显⽰没有通过的表达式,以及包含这个表达式的⽂件名和⾏号。

1.assert出现错误的时候会报错,指明在什么文件,哪一行

2. 如下图所示

http://www.xdnf.cn/news/1459.html

相关文章:

  • git提交
  • ctfhub-RCE
  • CDN加速http请求
  • 腾讯秋招面试题:bug生命周期中有哪些状态?
  • rl中,GRPO损失函数详解。
  • 需求质量验证-测试需求
  • GitLab_密钥生成(SSH-key)
  • 思科路由器密码绕过+重置
  • Vue 3中如何封装API请求:提升开发效率的最佳实践
  • Reactor编程模型介绍
  • Vue3 小功能记录:密码的显示与隐藏功能
  • WebXR教学 05 项目3 太空飞船小游戏
  • Synternet数据流正式上线Google Cloud Web3
  • FreeRTOS深度解析:队列集(Queue Sets)的原理与应用
  • Alertmanager的安装和详细使用步骤总结
  • 【锂电池剩余寿命预测】CNN卷积神经网络锂电池剩余寿命预测(Pytorch完整源码和数据)
  • 大模型RAG的召回模式
  • Vite vs Webpack 优势对比
  • 抱佛脚之学SSM六
  • 4.多表查询
  • AI与智能金融服务:如何利用AI分析大数据预测金融市场波动?
  • 获取发起DNS请求的真实进程及请求域名,不是取服务进程svchost.exe,做网络过滤或网络加速用得上。
  • Android 回显
  • 实验二 多线程编程实验
  • 云原生--CNCF-2-五层生态结构(成熟度3层分类,云原生生态5层结构)
  • 前端加密介绍与实战
  • 3dmax模型怎么导入酷家乐插件,材质贴图在,可优化不卡,可批量处理,无需打开一个个max,可批量转FBX/GLB/GLTF/OBJ/SU
  • Git简介与入门
  • 使用分布式ID作为MybatisID生成器
  • 【NVIDIA】Isaac Sim 4.5.0 Franka 机械臂参数解析