C++之指针总结

C++之指针总结
在这里插入图片描述

C++之指针

1 指针基础

在C++中,指针是至关重要的组成部分。它是C++语言最强大的功能之一,也是最棘手的功能之一。
指针具有强大的能力,其本质是协助程序员完成内存的直接操纵

在这里插入图片描述

1.1 指针的声明和赋值

在这里插入图片描述
声明:变量类型 * 指针变量名;
赋值:指针变量名 = 内存地址值;
int p;:声明整型变量,变量为p
int num =10
int * p;
:声明p为指针变量,p存放的为内存地址为什么为int?指针p存放num变量的地址,num本身为int变量。
变量类型(如上int)表示,指针(内存地址)指向的内存区域,存放的是整型数据


p=#:&:获取num的内存地址,提供给p
cout << p输出num变量地址
cout << *p输出10
在这里插入图片描述

1.2 指针解释

在这里插入图片描述

1.3 案例

#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int num =10;//标准的int类型变量,存放int值 10int*p;//声明了一个p指针变量,这个指针变量中记录的地址存的是int类型//指针变量,只能用来记录内存地址 p =&num;//将num变量的地址,赋予了p指针变量 cout <<"指针变量p中记录的地址是: "<< p << endl;//内存地址 cout <<"&num取地址为: "<<&num << endl;// cout <<"取指针变量记录地址中存放的数值为: "<<*p << endl;//10//直接展示对内存的操纵*p =20;//等同于num=20 cout <<"*p赋值后结果为:"<<*p << endl; cout <<"num结果为:"<< num << endl;return0;}}
指针变量p中记录的地址是:0x16443ffc04&num取地址为:0x16443ffc04 取指针变量记录地址中存放的数值为:10*p赋值后结果为:20 num结果为:20

2 野指针和空指针

野指针:被声明但未初始化(赋值)的指针。这个指针会指向随机的内存空间,可能导致未知问题。

在这里插入图片描述


普通变量是对数值进行操作,不会有安全问题,所以没有"野变量"一说。
指针对内存直接操作,所以一旦声明但未赋值,就是"野指针",一旦使用,后果不可预料。

在这里插入图片描述


为避免野指针,应养成良好的变成习惯,及时初始化,或将指针置为空指针更为安全。

在这里插入图片描述

2.1 案例

#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int*p;//声明指针变量(p被分配了8个字节的空间) cout << p << endl; cout <<"hello"<< endl;return0;}}
在这里插入图片描述

2.2 案例

#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{// int *p; //声明指针变量(p被分配了8个字节的空间)int*p =NULL;//将指针标记为空,无安全隐患int*p1 =nullptr;//将指针标记为空,无安全隐患*p =10;*p1 =10; cout <<"hello"<< endl;return0;}}

2.3 总结

声明会立刻分配内存,分配的内存不一定是干净的(比如其它程序残留)。
使用普通变量影响不大,但是指针不一样,会导致安全问题。
1.野指针:仅声明未赋值的指针。不可应用,因为其指向的内存区域是随机的、未知的。
2.空指针:将指针赋值为"空":NULL、nullptr,避免指向具体内存,更加安全。
3.空指针也不是正常的指针,只是过渡,指针最终要给与具体值,否则就不要用指针。

3 指针运算

尽管指针变量内记录的是内存地址,但仍可以进行基础的数学计算。
指针运算是对指针的基础型操作,非常适合操纵数组并配合做动态内存分配。

在这里插入图片描述


在这里插入图片描述

3.1 案例

#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int num =10;int*p =&num; cout <<"指针变量p记录的地址是: "<< p << endl; p++; cout <<"指针变量p进行加1操作,记录的地址是: "<< p << endl;double num1 =10;//double占用8个字节double*p1 =&num1; cout <<"指针变量p1记录的地址是: "<< p1 << endl; p1++; cout <<"指针变量p1进行加1操作,记录的地址是: "<< p1 << endl; p1 +=4; cout <<"指针变量p1进行加4操作,记录的地址是: "<< p1 << endl;int v[]={1,2,3,4,5};//v变量记录的就是数组地址,内存连续排列,每个元素的地址差值就是4个字节int*vp = v;//指针中记录了数组0下标元素的内存地址 cout <<"数组的第一个元素是: "<<*vp << endl; cout <<"数组的第一个元素是: "<< v[0]<< endl; cout <<"数组的第2个元素是: "<<*(vp +1)<< endl;//内存地址正好+4字节,正好是下一个元素的地址 cout <<"数组的第2个元素是: "<< v[1]<< endl;*(vp +2)=33; cout <<"数组的第3个元素是: "<<*(vp +2)<< endl; cout <<"数组的第3个元素是: "<< v[2]<< endl;int v2[]={1,2,3,4,5,6,7};int*p2 = v2;for(int i =0; i <sizeof(v2)/sizeof(v2[0]); i++){ cout <<*(p2 + i);}return0;}}
指针变量p记录的地址是:0x2b4d7ff6f4 指针变量p进行加1操作,记录的地址是:0x2b4d7ff6f8 指针变量p1记录的地址是:0x2b4d7ff6e8 指针变量p1进行加1操作,记录的地址是:0x2b4d7ff6f0 指针变量p1进行加4操作,记录的地址是:0x2b4d7ff710 数组的第一个元素是:1 数组的第一个元素是:1 数组的第2个元素是:2 数组的第2个元素是:2 数组的第3个元素是:33 数组的第3个元素是:331234567

3.2 练习

有数组:int v1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for循环遍历数组,使用指针取出每一个元素并打印输出。

#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int v2[]={1,2,3,4,5,6,7};int*p2 = v2;for(int i =0; i <sizeof(v2)/sizeof(v2[0]); i++){ cout <<*(p2 + i)<< endl;}return0;}}

4 内存动态分配

动态内存分配:即由程序员手动的进行内存空间的分配、内存空间的释放等内存管理操作。

在这里插入图片描述


C++代码中,变量、数组等对象的创建,是由C++自动分配内存的为,称之为(自动)静态内存分配。
(自动)静态内存管理,是不会进行内存空间的自动清理的。(无垃圾回收机制)
我们需要手动的管理内存,即手动分配,用完清理

在这里插入图片描述

4.1 案例

#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int*p =newint;//将new int对象的地址传给变量p*p =10; cout <<"new申请的4字节空间内,存放的是:"<<*p << endl;delete p;//释放内存int*p_arr =newint[5];//申请5元素存放int类型的数组空间// p_arr的地址,就是数组空间的内存区域的开头(第一个元素的位置) p_arr[0]=10;//等同于 *p_arr =10; p_arr[1]=20;//等同于 *(p_arr+1)=20; p_arr[2]=30;//等同于 *(p_arr+1)=20; p_arr[3]=40;//等同于 *(p_arr+1)=20; p_arr[4]=50;//等同于 *(p_arr+1)=20; cout <<"数组的第1个元素是: "<< p_arr[0]<< endl; cout <<"数组的第2个元素是: "<< p_arr[1]<< endl; cout <<"数组的第3个元素是: "<< p_arr[2]<< endl; cout <<"数组的第4个元素是: "<< p_arr[3]<< endl; cout <<"数组的第5个元素是: "<< p_arr[4]<< endl;*(p_arr)=0;*(p_arr +1)=1;*(p_arr +2)=2;*(p_arr +3)=3;*(p_arr +4)=4; cout <<"数组的第1个元素是: "<<*(p_arr)<< endl; cout <<"数组的第2个元素是: "<<*(p_arr +1)<< endl; cout <<"数组的第3个元素是: "<<*(p_arr +2)<< endl; cout <<"数组的第4个元素是: "<<*(p_arr +3)<< endl; cout <<"数组的第5个元素是: "<<*(p_arr +4)<< endl;delete[] p_arr;return0;}}
在这里插入图片描述

5 静态内存管理和手动管理方式区别

传统方式创建普通变量或数组,其内存由C++自动管理,称之为:
静态内存管理

  • 静态内存管理:不会清理用不到的内存空间
  • 动态内存管理:程序员手动管理内存空间

手动管理方式:

  • new运算符申请空间,提供该空间的指针(地址)
  • delete运算符申请的空间,仅用于new申请的空间

建议:写完new后,立刻写delete,然后再写业务逻辑代码

在这里插入图片描述


优势:
手动控制内存,避免内存空间浪费
劣势:
考验程序员水平,用的好效率高,用不好有反效果

5.1 练习

数组的内存控制
1.通过new运算符,申请10个int元素的数组内存空间并完成赋值。
2.通过for循环,基于指针形式取出数组元素并打印输出。
3.通过delete运算符,清理申请的内存空间。

#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int*p_arr1 =newint[10];for(int i =0; i <10; i++){*(p_arr1 + i)= i +1;}for(int i =0; i <10;++i){ cout <<*(p_arr1 + i)<< endl;}delete[] p_arr1;return0;}}

6 数组元素的移除

C++内置并未提供对数组元素进行增加(插入)、移除的功能,需要手动实现(vector容器提供,后续学习)。

6.1 思路

在这里插入图片描述

6.2 案例

#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{// 示例数组int*pArr =newint[5]{1,2,3,4,5};//创建一个新数组,将需要保留的复制到新数组中int*pNewArr =newint[4];//循环去遍历老数组。将需要的元素放入新数组中(不要的要跳过)for(int i =0; i <5; i++){if(i ==2){continue;}if(i >2){ pNewArr[i -1]= pArr[i];}else{ pNewArr[i]= pArr[i];}}delete[] pArr; pArr = pNewArr;//将老数组的指针指向新数组的内存空间for(int i =0; i <4; i++){ cout <<"新数组的元素是: "<< pNewArr[i]<< endl;}return0;}}
新数组的元素是:1 新数组的元素是:2 新数组的元素是:4 新数组的元素是:5

7 数组元素的插入

7.1 思路

在这里插入图片描述

7.2 案例

#include"iostream"usingnamespace std;//在下标1和3位置插入数字11和66intmain(){system("chcp 65001");{// 示例数组int*pArr =newint[5]{1,2,3,4,5};//创建一个新数组,将需要保留的复制到新数组中int*pNewArr =newint[7];int offset =0;//循环新数组,挨个进行元素填充(非插入的位置,填充老数组,插入位置填充新数组)for(int i =0; i <7; i++){if(i ==1){ pNewArr[i]=11; offset++;continue;}elseif(i ==3){ pNewArr[i]=66; offset++;continue;}//公式“老数组元素下标 + offset =新数组元素下标 pNewArr[i]= pArr[i - offset];}delete[] pArr; pArr = pNewArr;return0;}}

8 指针悬挂

指针指向区域已经被回收(delete),这种问题称之为:指针悬挂。

在这里插入图片描述


在这里插入图片描述

所以,总结出两点经验:
1.不要轻易进行指针之间相互赋值
2.delete回收空间前,确保此空间100%不再被使用

9 常量指针

9.1 指向const的指针

指向const的指针:表示指向区域的数据,是不变的,但可以更换指向。

在这里插入图片描述

9.1.1 案例

#include"iostream"usingnamespace std;//在下标1和3位置插入数字11和66intmain(){system("chcp 65001");{int num1 =10;int num2 =100;//1.指向const的指针,指向可变。数据不可变constint*p =&num1; cout <<"指针p当前指向的数据是: "<<*p << endl;// *p = 20; p =&num2; cout <<"指针p当前指向的数据是: "<<*p << endl;return0;}}
在这里插入图片描述

9.2 const指针

const指针:表示指针本身不可更改,但指向的数据可以更改。

在这里插入图片描述

9.2.1 案例

#include"iostream"usingnamespace std;intmain(){system("chcp 65001");{int num1 =10;int num2 =100;// 2. const指针,指向不可变,数据可变int*const p =&num1; cout <<"指针p当前指向的数据是: "<<*p << endl;*p=20; cout <<"指针p当前指向的数据是: "<<*p << endl;// p= &num2;return0;}}
在这里插入图片描述

9.3 指向const的const指针

指向const的const指针:指针和指向区域的值,都不可更改。

在这里插入图片描述

9.3.1 案例

#include"iostream"usingnamespace std;//在下标1和3位置插入数字11和66intmain(){system("chcp 65001");{int num1 =10;int num2 =100;// 3.指向const的const的指针constint*const p =&num1; cout <<"指针p当前指向的数据是: "<<*p << endl;// p=&num2;// *p = 20;return0;}}
在这里插入图片描述

9.4 总结

在这里插入图片描述

Read more

如何用腾讯云轻量应用服务器内置OpenClaw应用搭建OpenClaw并接入QQ、飞书机器人,下载skill,开启对话

如何用腾讯云轻量应用服务器内置OpenClaw应用搭建OpenClaw并接入QQ、飞书机器人,下载skill,开启对话

诸神缄默不语-个人技术博文与视频目录 如需OpenClaw下载安装、配置、部署服务可以联系:https://my.feishu.cn/share/base/form/shrcnqjFuoNiBPXjADvRhiUcB1B 我发现腾讯云买服务器可以用QQ钱包,这不得狠狠把我多年来抢的红包狠狠利用一下。 OpenClaw我之前玩了几天,现在把gateway关了,因为我感觉第一是感觉AI对于一些细微的执行逻辑还是绕不明白,而且API太慢了等得我着急,慢得我都不知道它是死了还是只是慢,不如我直接一个古法编程下去开发一个自己的工具。我本来是想拿OpenClaw当时间管理助手的,但是研究了一番感觉它作为整个人完整的时间/项目/文件系统/财务/生活管理助手的潜力还是很大的。但是,也就仅止于潜力了,跟OpenClaw绕记账怎么记实在是把我绕火大了……第二,正如网上一直宣传的那样,这玩意太耗token了,我的混元和Qwen免费额度几乎都秒爆,GLM也给我一下子烧了一大笔。我觉得这不是我的消费水平该玩的东西……主要我也确实没有什么用OpenClaw赚大钱的好idea。 但是我仍然觉得OpenClaw

【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

VR音游音符轨道系统开发实录与原理解析 在 VR 音游的开发过程中,音符轨道系统是最核心的交互与可视化部分。本文结合一次完整的开发实录,分享从核心原理与设计到VR内容构建的完整过程,帮助读者快速理解音符轨道系统的实现思路。 文章目录 * VR音游音符轨道系统开发实录与原理解析 * 一、实录结果 * 二、VR内容开发步骤 * 1. 准备音符与交互逻辑 * 2. 创建谱面 * 3. 绘制音轨 * 4. 预制件与音频替换 * 三、原理解析(音符轨道系统) * 1. 音符轨道(Note Track) * 2. 轨迹调节与偏移控制 * 3. 音符触摸激活 * 4. 谱面编辑工具(Editor 功能) * 四、总结与展望 * 1. 成果回顾:从零到一的核心突破 * 2. 技术总结:核心设计理念 * 3. 开发难点与问题反思 * 4. 优化策略与改进方向 * 5.

基于Jetson Nano与YOLOv5s的无人机道路抛洒物实时检测系统【附数据集+代码】

1. 为什么需要无人机道路抛洒物检测系统 想象一下你正开车行驶在高速公路上,突然前方出现一个不明物体——可能是掉落的纸箱、滚动的矿泉水瓶,甚至是散落的碎石。这些看似不起眼的小东西,在高速行驶状态下可能酿成大祸。传统的人工巡检方式效率低下,往往需要工作人员冒着危险在车流中穿行,而且很难做到全天候监控。这就是为什么我们需要一个智能化的解决方案。 我在实际测试中发现,使用无人机搭载视觉检测系统可以完美解决这个问题。无人机能够从高空俯拍道路,避开地面交通干扰;边缘计算设备Jetson Nano则让实时分析成为可能;而YOLOv5s算法就像给无人机装上了"火眼金睛",能瞬间识别出那些危险的抛洒物。这三者的结合,相当于给道路安全装上了全天候的智能哨兵。 2. 硬件选型与系统搭建 2.1 Jetson Nano的边缘计算优势 Jetson Nano这块小板子真是让我又爱又恨。爱的是它128核Maxwell GPU带来的强大算力,恨的是在资源有限的情况下做优化确实需要费些心思。不过经过多次调试,我发现它确实是无人机视觉处理的绝配——功耗仅5-10W,重量不到100克,却能流畅运行YOLOv