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时出现npm error code ENOENT npm error syscall spawn git报错的解决方案

安装openclaw时出现npm error code ENOENT npm error syscall spawn git报错的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为ZEEKLOG博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理解,而且能够帮助新手快速入门。 本文主要介绍了安装openclaw时出现npm error code ENOENT npm error syscall spawn git报错的解决方案,希望能对使用openclaw的同学们有所帮助。 文章目录 * 1. 问题描述 * 2. 解决方案 1. 问题描述 今天在使用命令安装openclaw时,却出现了npm error code ENOENT和npm error syscall spawn git的错误提示,具体报错信息如下图所示: 在经过了亲身的实践后,终于找到了解决问题的方案,最终将逐步的操作过程总结如下。希望能对遇到同样bug的同学们有所帮助。

By Ne0inhk
OpenCode 免费模型深度评测:四大开源模型场景化对比与选型指南

OpenCode 免费模型深度评测:四大开源模型场景化对比与选型指南

在开源大语言模型(LLM)生态中,OpenCode 凭借其多样化的免费模型矩阵(如 Trinity Large Preview、Big Pickle、MiniMax M2.5 Free、GPT-5 Nano)吸引了开发者与企业的广泛关注。本文将从技术架构、性能表现、适用场景等维度,深度解析这四大模型的差异化优势,并提供选型建议。 1. Trinity Large Preview:超大规模稀疏模型的“创意引擎” 开发者:Arcee AI 核心架构:400B 参数稀疏混合专家(MoE)架构,每 token 仅激活 13B 参数 上下文窗口:512K tokens(约 75 万字) 适用场景:创意写作、

By Ne0inhk
《开源圈聚焦的技术新作:讯飞 Astron Agent 的 “工作流编排 + MCP 工具集”,如何降低企业智能体开发门槛》

《开源圈聚焦的技术新作:讯飞 Astron Agent 的 “工作流编排 + MCP 工具集”,如何降低企业智能体开发门槛》

前引:今天我们不谈趣味互动类的小智能体,而是聚焦又一个开源的企业级智能体 “基建”—— 讯飞星辰推出的 Astron Agent。作为讯飞首个开源的企业级智能体平台,它把 AI 工作流编排、RPA 自动化、MCP 工具集打包成了可直接复用的基座,刚上线 GitHub 就拿下 6k+ Star,连科技圈都在讨论它怎么降低企业做智能体的门槛! 本文将聚焦于:与其同时开源的RPA介绍及智能体平台Astron Agent 中各个工具的详细使用                                    不是广告!不是广告!不是广告!真心推荐! 目录  【一】Astron智能体平台介绍 【二】RPA介绍 【三】Astron部署登录 (2)登录过程 (2)全程体验 【四】几个重要工具详解 (1)什么是系统/用户提示词 (2)代码节点 (3)什么时候用知识库 (4)

By Ne0inhk

Jenkins Git 克隆失败深度解析:从 “Connection reset by peer“ 到彻底解决

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[[email protected]] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? * 专栏导航: 码农阿豪系列专栏导航 面试专栏:收集了java相关高频面试题,面试实战总结🍻🎉🖥️ Spring5系列专栏:整理了Spring5重要知识点与实战演练,有案例可直接使用🚀🔧💻 Redis专栏:Redis从零到一学习分享,经验总结,案例实战💐📝💡 全栈系列专栏:海纳百川有容乃大,可能你想要的东西里面都有🤸🌱🚀 目录 * Jenkins Git 克隆失败深度解析:从 "Connection reset by peer" 到彻底解决 * 引言:持续集成的脆弱环节

By Ne0inhk