C++指针详解
旧文更新:两三年的旧文了,一直放在电脑里,现在直接传上CSDN
一、指针的概念
1.1 指针
程序运行时每个变量都会有一块内存空间,变量的值就存放在这块空间中。程序可以通过变量名直接访问这块空间内的数据,这种访问方式称之为直接访问。
而内存中每一个字节都会有一个编号,称之为内存地址。我们可以通过直接访问内存地址从而找到变量。在C++中,有一种指针变量专门用于存储内存地址,我们通过访问指针变量,可以得到对应变量的内存地址,从而实现对该变量的访问。这就是间接访问。
指针存储的是一个内存地址,他的一个重要用途就是通过指针间接访问所指向的地址中的内容。指针定义如下:
类型名 *指针变量名;
比如定义两个指针p1和p2:
int *p1, *p2;
1.2 指针的基本操作
1.指针变量的赋值
指针变量一般用于保存同一个程序中某个变量的地址,以便日后使用指针变量进行间接访问。因此赋值有两种办法:一是将本程序的某一变量地址赋值给指针变量,另一种是将指针变量赋值给另一个指针变量。
让指针变量只想某一变量,就是将一个变量的地址存入指针变量,但是程序员并不知道变量在内存中的地址,为此C++提供了一个取地址运算符&,用于获取指定变量的地址,例如:
int *p, x;
p=&x;
这样就成了将x变量的地址放入到指针p中,上述语句等价于int x, *p=&x
和普通变量一样,如果没有给新定义的指针变量赋值,C++会给它随机赋以初址,这会导致内存泄漏,因此为了避免误操作,不要引用没有被赋值的指针,并且某个指针被创建了但暂且不用,应该给它赋以NULL值。
需要注意的是,不同变量类型的指针之间不能相互赋值,比如int x;double *p =x;
这种操作是不允许的,因为指针是使用变量类型大小来判断边界的。在内存中int是4字节大小的,而double是8字节大小的。那么double指针会以其存储的地址为起点,读取往后的8个字节的内容,很明显,这超过了int型的大小限制。
2.指针变量的访问
C++中定义了一个取指针指向值的运算符*,该运算符是一个一元运算符,他的运算对象是一个指针,运算符会根据指针的类型返回其指向的值。这在指针定义之后使用。
也就是说指针在定义的时候需要在变量名前加*,但是在后续使用指针变量时候是不需要加*的,指针p在被定义后再使用*p的话会直接得出指针所指的变量的值,下列是一个简单的实例
int a=2, *p=&a;
cout<<*p<<" "<<p<<" "<<a;
我们可以看到输出结果是:2 0x16d81b868 2。也就是在完成定义后,p表示内存地址,*p表示该内存地址存入的值。
3.统配指针类型void
指针的基本类型可以为void,这只说明了这个变量中存放的是内存地址,但是并未说明存放何种类型的地址,因此任何类型的指针都可以和void类型指针相互赋值。
4.指针和常量限定符const
使用const修饰指针有如下三种用法:
1.指向常量的指针(常量指针):是一个执行内容是常量的指针变量,指针可以更改指向的对象,但是不能改变指向对象的值。
const int *p = &x;
2.指针常量:指针本身是一种常量,无法改变指针的值,但是可以改变指向的变量的值
int *const p=&x;
3.指向常量的指针常量:指针本身不可变,所指向的值也不能变
const int *const p = &x;
二、指针和数组
2.1 指针运算
指针保存的是一个内存地址,本质上是一个整数,因此对整数进行算术运算也是十分理算当然得。但是对于指针执行乘除运算是没有意义的,因为这会使得指针指向不可知的领域,C++中只考虑了指针的加减运算。对指针执行+1,那么他会增加一个基本类型的长度,比如对一个int *p=1000执行p++,那么p=1004,因为整形变量的大小为4。
2.2 用指针访问数组
在C++中,一个数组的数组名保存的是数组的起始地址,也就是说,实际上数组名就是一个指针,不过它是一个指针常量。不过数组在声明时除了将数组首地址赋值给了数组名外,还进行了空间申请的行为。我们完全可以将数组名赋值给一个指针,那么该指针就具备了数组名的行为
三、动态内存分配
3.1 动态变量
有时候在C++中我们需要动态地新增变量,或者说动态指定数组的大小,这就需要使用到动态变量机制了。动态变量指的是在写成是时无法确定它们的存在,只有程序运行起来,随着程序的运行可以根据程序的需求动态产生和消亡的变量。由于动态变量不可以在程序中定义,因此也没法给他们取名字,因此动态变量的访问需要通过指向动态变量的指针来实现间接访问
3.2 动态变量的创建
C++的动态变量的创建使用的运算符是new,该运算符可以创建一个简单变量或者一个数组,格式如下:
new 类型名;
这个操作在内存中称之为堆的区域申请一块能够存放相应数据类型的数据空间,完成操作后会返回该空间的首地址。比如要动态产生一个int型变量,并且将20赋值给该变量,则操作如下:
int *p;
p = new int;
*p = 20;
需要注意,new操作是需要指定类型的,因此它的结果只能赋值给同类指针。
用new操作可以创建一个一维数组,格式如下:
new 类型名[元素个数];
动态数组和普通数组最大的区别在于,数组的大小不需要静态指明一个常量,可以在运行时赋予,因此更加灵活。比如:
p = new int[2*n];
3.3 动态变量的消亡
在C++运行期间,动态变量不会消亡,因此要回收动态变量的空间就必须显式地使之消亡。要回收某个动态变量,可以使用delete操作。操作如下:
delete 指针变量
该操作会回收指针指向的空间,例子如下:
int *p = new int(10);
delete p;
如果需要回收的是一个动态数组,可以使用delete [] 指针变量
一旦释放了这些内存区域,堆管理器会重新回收这些区域,虽然指针还会指向这个区域,但是已经不能再访问和使用这些区域
在动态变量的使用中,最常见的问题是内存泄漏,也就是用动态变量机制申请了一个动态变量,但是在不需要使用这个动态变量的时候没有delete,或者在变量没有delete之前,让该动态变量的指针指向另外一个动态变量,此时你就彻底弄丢这个动态变量了!堆管理器以为你仍在使用它,但是你自己都找不到它在哪了。为了避免上述变量,应该及时使用delete清除不需要使用的动态变量。
四、指针和函数
4.1 指针作为形式参数
函数的参数可以传入指针变量,作用是将一个变量的地址传入到一个函数中,指针传递可以降低参数传递的开销,并且让主函数和被调用函数共享一块内存空间,指针作为形式参数是一种”址传递“,在函数中对指针所指向的变量进行操作,也会改变该变量的值,此时在主函数中读取该变量也是被改变的。而一般参数的”值传递“,传递的形式参数的作用域只会是在被调用函数内部,对值传递的参数进行修改只会在被调函数中起改变,而不会影响到主函数。
但是数组名是一种特殊的情况,当数组名作为函数的参数时,形式参数和实际参数是共享了同一块内存空间,因此函数内对数组形式参数的任何修改都是对实际参数数组的修改。
字符串是作为字符数组存储的,因此传递进去的也是指针,但是字符串会以’\0’结尾,所以可以不传递字符数组的长度
4.2 返回指针的函数
函数返回值可以是一个指针,表示函数的返回值是一个指针只需要在函数名之前加一个*号,此时返回的值必须是一个指针变量。比如:
五、引用类型
5.1 引用类型
指针提供了通过一个变量间接访问另一个变量的能力。为了获得指针的效果,又要避免指针的问题,C++提供了引用类型这种新的类型。
1.引用的声明和使用
引用就是给变量取一个别名,使得一块内存空间可以通过几个变量名在访问。声明引用类型的变量需要在变量名前加上符号&,并且必须指定初值。比如:
int i;
int &j = i;
其中第二个语句中定义了变量j是变量i的别名,当编译器遇到这个语句的时候,他并不会为变量j分配空间,而是只是将i和j的地址关联起来,i和j用的是同一内存单元,通过j可以访问i的空间。引用实际上是一种隐式指针,每次使用引用变量可以不用书写运算符"*",因此简化了程序的书写。
定义引用类型变量时,必须在变量名前加上符号&用于区别和普通变量的区别。并且定义时就必须对其进行初始化并赋值。
5.2 引用传递
1.引用传递参数
引用的主要目的是将引用作为参数的函数,最经典的是swap函数,如果swap函数使用指针书写,则如下:
void swap(int* a, int* b){int c;c = *a;*a = *b;*b = c;
}
很显然,如果使用指针传递,那么需要在每一个运算符前都加上指针运算符*,但是使用引用传递只需要像如下一样书写:
void swap(int& a, int& b){int c;c = a;a = b;b = c;
}
可以看到,使用引用符号后,不需要书写这么多*号了。在使用引用类型参数的时候需要注意,调用时对应的实际参数必须为左值表达式
5.3 返回引用的函数
函数的返回值也可以是一个引用,代表返回函数内某个变量的引用。
相关文章:
C++指针详解
旧文更新:两三年的旧文了,一直放在电脑里,现在直接传上CSDN 一、指针的概念 1.1 指针 程序运行时每个变量都会有一块内存空间,变量的值就存放在这块空间中。程序可以通过变量名直接访问这块空间内的数据,这种访问方…...
tauri+vite+vue3开发环境下创建、启动运行和打包发布
目录 1.创建项目 2.安装依赖 3.启动项目 4.打包生成windows安装包 5.安装打包生成的安装包 1.创建项目 运行下面命令创建一个tauri项目 pnpm create tauri-app 我创建该项目时的node版本为16.15.0 兼容性注意 Vite 需要 Node.js 版本 14.18,16。然而&#x…...
安卓进阶系列-系统基础
文章目录计算机结构冯诺依曼结构哈弗结构冯诺依曼结构与哈弗结构对比安卓采用的架构安卓操作系统进程间通讯(IPC)内存共享linux内存共享安卓内存共享管道Unix Domain Socket同步常见同步机制信号量Mutex管程安卓同步机制安卓中的Mutex安卓中的ConditionB…...
10 Wifi网络的封装
概述 Wifi有多种工作模式,比如:STA模式、AccessPoint模式、Monitor模式、Ad-hoc模式、Mesh模式等。但在IPC设备上,主要使用STA和AccessPoint这两种模式。下面分别进行介绍。 STA模式:任何一种无线网卡都可以运行在此模式,这种模式也是无线网卡的默认模式。在此模式下,无线…...
手把手的教你安装PyCharm --Pycharm安装详细教程(一)(非常详细,非常实用)
简介 Jetbrains家族和Pycharm版本划分: pycharm是Jetbrains家族中的一个明星产品,Jetbrains开发了许多好用的编辑器,包括Java编辑器(IntelliJ IDEA)、JavaScript编辑器(WebStorm)、PHP编辑器&…...
开发板与ubantu文件传送
接下来的所以实验都通过下面这种方式发送APP文件到开发板运行 目录 1、在ubantu配置 ①在虚拟机上添加一个桥接模式的虚拟网卡 ②设定网卡 ③在网卡上配置静态地址 2、开发板设置 ①查看网卡 ②配置网卡静态ip 3、 测试 ①ping ②文件传送 传送报错情况 配置环境&#…...
如何成为一名优秀的网络安全工程师?
前言 这是我的建议如何成为网络安全工程师,你应该按照下面顺序学习。 简要说明 第一件事你应该学习如何编程,我建议首先学python,然后是java。 (非必须)接下来学习一些算法和数据结构是很有帮助的,它将…...
面试问题之高并发内存池项目
项目部分 1.这个项目是什么? 高并发内存池的原型是谷歌一个开源项目,tcmalloc,而这个项目,就是tcmalloc中最核心的框架和部分拿出来进行模拟。他的作用就是在去代替原型的内存分配函数malloc和free。这个项目涉及的技术有,c&…...
如果阿里巴巴给蒋凡“百亿补贴”
出品 | 何玺 排版 | 叶媛 2021底,阿里内部进行组织架构大调整,任命蒋凡为阿里海外商业负责人,分管全球速卖通和国际贸易(ICBU)两个海外业务,以及Lazada等面向海外市场的多家子公司。 一年时间过去&#x…...
Linux版本现状
Linux的发行版本可以大体分为两类,一类是商业公司维护的发行版本,一类是社区组织维护的发行版本,前者以著名的Red Hat(RHEL红帽)为代表,后者以Debian为代表。Red HatRedhat,应该称为Redhat系列&…...
Winform中实现保存配置到文件/项目启动时从文件中读取配置(序列化与反序列化对象)
场景 Winform中实现序列化指定类型的对象到指定的Xml文件和从指定的Xml文件中反序列化指定类型的对象: Winform中实现序列化指定类型的对象到指定的Xml文件和从指定的Xml文件中反序列化指定类型的对象_winform xml序列化_霸道流氓气质的博客-CSDN博客 上面讲的序…...
基于python的超市历年数据可视化分析
人生苦短 我用python Python其他实用资料:点击此处跳转文末名片获取 数据可视化分析目录人生苦短 我用python一、数据描述1、数据概览二、数据预处理0、导入包和数据1、列名重命名2、提取数据中时间,方便后续分析绘图三、数据可视化1、美国各个地区销售额的分布&…...
GPT-4技术报告
摘要 链接:https://cdn.openai.com/papers/gpt-4.pdf 我们汇报了GPT-4的发展,这是一个大规模的多模态模型,可以接受图像和文本输入并产生文本输出。虽然在许多现实场景中,GPT-4的能力不如人类,但它在各种专业和学术基…...
前端性能优化
总结 使用打包工具对代码进行打包压缩;引入css时采用link标签,并放入头部,使其与文档一起加载,减少页面卡顿时间;尽量减少dom结构的重排和重绘;使用css雪碧图,减少网络请求;对不同分…...
尚医通-(三十三)就诊人管理功能实现
目录: (1)前台用户系统-就诊人管理-需求说明 (2)就诊人管理-接口开发-列表接口 (3)就诊人管理-接口开发-其他接口 (4)前台用户系统-就诊人管理-前端整合 ࿰…...
《Spring Boot 趣味实战课》读书笔记(二)
牛刀小试——五分钟入门 Spring Boot 万物皆可 Hello World 创建一个 Web 工程 填写项目信息 选择依赖 从 IDEA 打开下载好的 Spring Boot 工程: 完成核心代码 创建 HelloController 类并编写 hello 方法 创建一个 HelloController 类,或者选择 Fi…...
Spring Cloud -- GateWay
为什么需要网关在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用。这样的话会产生很多问题,例…...
【C语言】memcpy , memset等内存操作函数使用方法与注意事项
这个章节,我们探讨C语言内存操作函数。 重点介绍处理内存操作函数使用和注意事项 和内存函数如何模拟实现。 内存函数所需头文件 #include<string.h> 文章目录memcpymemcpy 函数模拟实现memmovememmove 函数模拟实现memcmpmemcmp 函数模拟实现memsetmemset 函…...
尚融宝04-mybatis-plus插件和条件构造器
目录 一、分页插件 1、添加配置类 2、添加分页插件 3、测试分页 二、XML自定义分页 1、UserMapper中定义接口方法 2、定义XML 3、测试 三、乐观锁 1、场景 2、乐观锁方案 3、乐观锁实现流程 4、优化流程 四、wapper介绍 1、Wrapper家族 2、创建测试类 五、Qu…...
面试重难点问题(C++)
持续更新!!!!! 网络部分 1.问,四次挥手的过程,和双方状态变化? 挥手这前,两边都是established状态,客户端发起断开请求,向服务器发送fin请求&…...
androidx.appcompat 升级到1.5.1 趟过的坑
APP 要上google play,Android SDK 版本要升级到32;接了一个第三方SDK,不巧的是这个SDK引用appcompat是1.5.1,顺手把appcompat 包升级到1.5.1,这草率的一升,带来的不止一地鸡毛,还有精神上被残忍…...
[C++]反向迭代器
目录 前言: 1 对反向迭代器的构造思想 2 实现反向迭代器 3 完整代码 前言: 本篇文章主要介绍了STL容器当中的反向迭代器,可能有朋友会说:“反向迭代器有什么好学的?不一样还是迭代器吗,我正向能写出来&…...
解析Python编程中的包结构
假设你想设计一个模块集(也就是一个“包”)来统一处理声音文件和声音数据。通常由它们的扩展有不同的声音格式,例如:WAV,AIFF,AU),所以你可能需要创建和维护一个不断增长的各种文件格…...
【前端】深入浅出缓存原理
缓存的基本原理 对于前端来说,缓存主要分为浏览器缓存(比如 localStorage、sessionStorage、cookie等等)以及http缓存,也是本文主要讲述的。 当然叫法也不一样,比如客户端缓存大概包括浏览器缓存和http缓存 所谓htt…...
单调栈图文详解(附Java模板)
🍏🍐🍊🍑🍒🍓🫐🥑🍋🍉🥝 啥是"单调栈",它能解决什么样的问题? 文章目录🦩单调栈的概念&a…...
彻底理解Session、Cookie、Token,入门及实战
文章目录Session Cookie的使用Token的使用Session Cookie的使用 1. Session存储数据 HttpSession session request.getSession(); //Servlet底层通过的SESSIONID,获取Session对象。 session.setAttribute("loginTime",new Date()); out.println(&q…...
为什么运营商大数据可以精准获客?
“获客难”,“获客成本高”,一直是困扰企业的大问题,身边的许多朋友在吐槽客户的意向度不高,总是无法成交,员工非常积极主动去跟踪客户了,但始终事倍功半,这就像是老人们常说的一句老话“热脸贴…...
【数据结构】栈的实现
💯💯💯 本篇主要利用数组来实现栈,对于栈的各种操作都作详细介绍,压栈,出栈以及获取栈中元素的操作都是学习栈的必备知识,快来学起来吧!!!©Ⅰ.栈的概念及…...
【链表OJ题(六)】链表分割
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:数据结构 🎯长路漫漫浩浩,万事皆有期待 文章目录链表OJ题(六)1. 链表…...
C++类中的三大函数(构造,析构,拷贝)
下面一段话与大家共勉:每个人的一生都会遇到很多边界,有些边界可以突破,有些则不能。那些无法突破的边界就是你的极限,而划分边界的标准就是“阈值”。每次突破阈值之后,人生轨迹就会发生剧烈变化,其间需要…...
怎么自己做个网站做链接跳转/seo算法培训
---------------------- Windows Phone 7手机开发、.Net培训、期待与您交流! ---------------------- 一、javascript调用C#代码解决方案 // 第一种情况: 1.后台方法: protected string CsharpVoid(string strCC) { return strCC; …...
电子商务网站建设与维护期末/少儿培训
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼第一:数据库之对比:相对于,ifix中的过程数据库,.net更偏向于sqlserver,orcle,mysql,db2类型的关系数据库。ifix之向关系数据库中更多的是向access数据啼中传送相关报警的历…...
烟台开发区人才市场招聘信息/合肥网络公司seo建站
奔小康赚大钱Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2325 Accepted Submission(s): 1020Problem Description传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房…...
安陆 网站建设/网站seo优化案例
条件:1八位数;2.以领开头;3.末尾要依次递增 <script type"text/javascript">function Account(num,a){ // num以领开头的8位数,a依次递增 //初始的a为数字var s a.toString(); // 数字转字符串var b s.…...
衡阳网站建设衡阳千度网络/友链对网站seo有帮助吗
“微软实现企业信息系统远程客户端的安全技术及应用-石家庄站活动”召开在即!热忱期待您的光临!感谢您对本次活动的热情参与! 城 市:石家庄 时 间:2005年11月16日 13:30-17:…...
asp.net 网站管理工具/seo综合查询网站源码
MySQL8 创建用户,设置修改密码,授权 MySQL5.7可以 (创建用户,设置密码,授权) 一步到位 👇 GRANT ALL PRIVILEGES ON *.* TO 用户名% IDENTIFIED BY 密码 WITH GRANT OPTION👆这样的语句在MySQL8.0中行不通, 必须 创设和授权 分步执行👇 CR…...