C++系列第九篇 数据类型下篇 - 复合类型(指针高级应用)
系列文章
C++ 系列 前篇 为什么学习C++ 及学习计划-CSDN博客
C++ 系列 第一篇 开发环境搭建(WSL 方向)-CSDN博客
C++ 系列 第二篇 你真的了解C++吗?本篇带你走进C++的世界-CSDN博客
C++ 系列 第三篇 C++程序的基本结构-CSDN博客
C++ 系列 第四篇 C++ 数据类型上篇—基本类型-CSDN博客
C++ 系列 第五篇 C++ 算术运算符及类型转换-CSDN博客
C++系列第六篇 数据类型下篇 - 复合类型(数组及字符串)-CSDN博客
C++系列第七篇 数据类型下篇 - 复合类型(结构体、共用体及枚举)-CSDN博客
C++系列第八篇 数据类型下篇 - 复合类型(指针及动态内存申请)-CSDN博客
前言
这一章节进行复合类型最后一部分的介绍,主要是指针的一些高级应用,包括指针和数组的的关系,指针和字符串的关系,指针和结构的关系, 变量基于内存位置进行的分类。 还会简单介绍下 C++特有的动态数组,vector 和 array。
指针和数组
进行过C编程的人一定进行过指针和数组等价使用,即申请的是数组,按指针操作,或者一个指针指向一块申请的内存,按数组进行操作。 C++中指针和数组也可以进行等价使用。指针和数组基本等价的原因在于指针算术和C++内部处理数组的方式。
首先,将整数变量加 1 后,其值将增加1:但将指针变量加1 后,增加的量等于它指向的类型的字节数。将指向 double 的指针加1 后,如果系统对 double 使用 8 个字节存储,则数值将增加 8;将指向short 的指针加1 后,如果系统对 short 使用 2 个字节存储,则指针值将增加 2。
如上的示例除了说明指针的数值计算外,还有一个比较重要的点就是将数组名解释为地址。大部分情况两者可以等价操作,可以像示例中一样使用指针的数值计算一样进行数组的数值计算,同时也能像取数组元素一样操作指针。
我们为什么说大部分情况可以等价操作,那就是有不等价的情况,两种情况,一是 指针是一个变量,可以像示例中 ptr = ptr+1; 即可以修改指针的值,而数组名不可以修改,它是常量;二是使用sizeof 进行计算,对数组应用 sizeof 运算符得到的是数组的长度,而对指针应用 sizeof 得到的是指针的长度,即使指针指向的是一个数组。
还有一个平常容易忽略的点是数组的地址 ,对数组取地址时,数组名不会被解释为其地址。我们上边说了数组名被解释为数组的地址,相当于第一个数组元素的地址,当对数组名应用地址运算符时,得到的是整个数组的地址,从数字上说,这两个地址相同;但从概念上说,&ptr[0](即 ptr)是一个4 字节内存块的地址,而&ptr是一个20 字节内存块的地址。因此,表达式ptr+1将地址值加4,而表达式&ptr+1 将地址加 20。换句话说,ptr是一个int 指针,而&ptr是一个这样的指针,即指向包含5个元素的int数组(int(*)[5])。具体使用的时候一定要注意。
指针和字符串
有三个特别需要注意的点
1、在cout 和多数 C++表达式中,char 数组名、char 指针以及用引号括起的字符串常量都被解释为字符串第一个字符的地址。
如果给 cout 提供一个字符的地址,则它将从该字符开始打印,直到遇到空字符为止。这意味着可以将指向char 的指针变量作为cout 的参数,因为它也是char 的地址。
cstring 中的strcpy 具体实现如图,可以看到从第一个字符的地址开始进行处理,直到碰到结束符为止
2、在将字符串读入程序时,应使用已分配的内存地址。该地址可以是数组名,也可以是使用 new初始化过的指针。
字符串读入一定是要有具体内存去存储它的,否则胡乱存储到未知内存的话,就会造成内存访问异常,进而出现程序挂死。而数组本身是一个已经由编译器分配好内存的的变量,new初始化过的指针也指向了一个动态分配好的内存。但是要特别注意,数组或者new 分配的内存要足够大,能够容纳需要读入的字符串,否则会造成内存访问溢出。
3、字符串赋值给字符数组时要使用strcpy 或者 strncpy 等拷贝函数, 直接 "array = ptr" 这种操作是不可取的,因为ptr 是一个指针,其值是一个地址,直接赋值相当于 把ptr 指向的地址 赋值给array 数组了,但是array 数组本身是有一个地址的,编译器不允许修改 数组变量的地址
指针和结构体
可以运行时创建动态结构,“动态”意味着内存是在运行时,而不是编译时分配的。由于类与结构非常相似,结构的大部分技术也适用于类。将new 用于结构由两步组成:创建结构和访问其成员。要创建结构,需要同时使用结构类型和new。例如,要创建一个未命名的 inflatable 类型,并将其地址赋给一个指针,可以这样做:inflatable *ps = new inflatable; 这将把足以存储 inflatable 结构的一块可用内存的地址赋给 ps。
动态创建的结构,不能将成员运算符句点用于结构名,因为这种结构没有名称,只是知道它的地址。需要使用箭头成员运算符(->) 来访问成员,这点和C 语言完全一眼。。例如,如果ps 指向一个inflatable 结构,则 ps->price 是被指向的结构的 price 成员。
另一种访问结构成员的方法是,如果 ps 是指向结构的指针,则*ps 就是被指向的值--结构本身。由于*ps 是一个结构,因此(*ps).price 是该结构的 price 成员。但基本没这么用的,平白增加程序的复杂度。
局部变量、静态变量及动态变量
根据分配内存的方法,或者是变量所属内存位置的不同, C及 C++有 3 种管理数据内存的方式:自动存储、静态存储和动态存储(有时也叫作自由存储空间或堆), 对应的变量分别也叫局部变量、静态变量及动态变量。
在函数内部定义的常规变量使用自动存储空间,被称为自动变量(automatic variable),这意味着它们在所属的函数被调用时自动产生,在该函数结束时消亡。自动变量是一个局部变量,其作用域为包含它的代码块。代码块是被包含在花括号中的一段代码。注意是代码块,而不是函数,我们目前为止举例都是整个函数举例,但其实一个函数里也可以分不同代码块的,如下所示, value 整形变量定义时使用{} 进行了包含, 所以属于一个单独的代码块,在代码快外使用,提示未定义。
静态存储是整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种: 一种是在函数外面定义它;另一种是在声明变量时使用关键字static, 如 static double fee=56.50;。
自动存储和静态存储的关键在于,这些方法严格地限制了变量的寿命。变量可能存在于程序的整个生命周期(静态变量),也可能只是在特定函数被执行时存在(自动变量)。
动态存储new 和delete 运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内存池,这在 C++中被称为自由存储空间(free store)或堆(heap)。该内存池同用于静态变量和自动变量的内存是分开的。new 和delete 使得一个变量能够在一个函数中分配内存,而在另一个函数中释放它。因此,数据的生命周期不完全受程序或函数的生存时间控制。
与使用常规变量相比,使用 new 和delete 让程序员对程序如何使用内存有更大的控制权。然而,内存管理也更复杂了。在栈中,自动添加和删除机制使得占用的内存总是连续的,但new和delete的相互影响可能导致占用的自由存储区不连续,这使得跟踪新分配内存的位置更困难。
如果使用new 运算符在自由存储空间(或堆)上创建变量后,没有调用 delete,则即使包含指针的内存由于作用域规则和对象生命周期的原因而被释放,在自由存储空间上动态分配的变量或结构也将继续存在。实际上,将会无法访问自由存储空间中的结构,因为指向这些内存的指针无效。这将导致内存泄漏。被泄漏的内存将在程序的整个生命周期内都不可使用;这些内存被分配出去,但无法收回。
我们在上一篇也提到过,指针时危险的,因为它们允许执行对计算机不友好的操作,如使用未经初始化的指针来访问内存或者试图释放同一个内存块两次,或者向上边提到的,因为未进行delete 操作,造成内存泄漏。大家使用的时候一定要特别注意。
数组的替代品
模板类 vector 和array是数组的替代品
模板类 vector 类似于string 类,是一种动态数组。可以在运行阶段设置vector 对象的长度,可在末尾附加新数据,还可在中间插入新数据。基本上,它是使用 new 创建动态数组的替代品。实际上,vector类确实使用 new 和 delete 来管理内存,但这种工作是自动完成的。
要使用vector 对象,必须包含头文件vector。其次,vector 包含在名称空间std 中,因此可使用using 编译指令、using 声明或std::vector。第三,模板使用不同的语法来指出它存储的数据类型。第四,vector 类使用不同的语法来指定元素数。
如下vi 是一个空的vector<int>对象 。 使用时可以使用对应的方法 resize 重新指定需要的大小并 按正常数组方式进行使用。
vd 是一个有三个元素的 vector<double> 对象,定义时分配了空间,所以可以直接访问范围内元素。
vector 类的功能比数组强大,但付出的代价是效率稍低。如果需要的是长度固定的数组,使用数组是更佳的选择,但代价是不那么方便和安全。鉴于此,C++11 新增了模板类array,它也位于名称空间std中。与数组一样,array 对象的长度也是固定的,也使用栈(静态内存分配),而不是自由存储区,因此其效率与数组相同。 好多学习资料上说array 有边界检查,不够准确,不是所有情况下都有边界检查,如下所示,使用max_size方法 ,获取到的确实 是定义时候的大小,但是 可以像C数组一样,超边界赋值,编译器并没有报错。只有通过at() 方法 时 才会捕捉这种越界错误,并进行停止,但是效率会 降低。
到这里为止,符合类型就都总结完了,意味着数据类型也都学完了,下一篇我们将开始表达式和语句的总结学习。
相关文章:
C++系列第九篇 数据类型下篇 - 复合类型(指针高级应用)
系列文章 C 系列 前篇 为什么学习C 及学习计划-CSDN博客 C 系列 第一篇 开发环境搭建(WSL 方向)-CSDN博客 C 系列 第二篇 你真的了解C吗?本篇带你走进C的世界-CSDN博客 C 系列 第三篇 C程序的基本结构-CSDN博客 C 系列 第四篇 C 数据类型…...
python三大开发框架django、 flask 和 fastapi 对比
本文讲述了什么启发了 FastAPI 的诞生,它与其他替代框架的对比,以及从中汲取的经验。 如果不是基于前人的成果,FastAPI 将不会存在。在 FastAPI 之前,前人已经创建了许多工具 。 几年来,我一直在避免创建新框架。首先&…...
html基础2
视频video <video src"视频的路径"controls"控制播放、暂停、音量等"autoplay"自动播放"loop"循环播放"width"视频播放器的宽度"height"视频播放器的高度"> </video>还有做浏览器兼容的方式…...
基于博弈树的开源五子棋AI教程[5 启发式搜索]
文章目录 1 最大化攻击者/最小化防守者排序2 置换表启发3 杀手表启发4 历史表启发历史表以及杀手表的维护初始化追加杀手表项清空杀手表 启发式搜索的姿势千奇百怪,本文只讨论一下几种 //搜索空间 #define Search_Space_MVA 0 //最优价值攻击者[分数最大] #d…...
JavaScript原型,原型链 ? 有什么特点?
一、原型 JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象 当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个…...
Unity 问题 之 ScrollView ,LayoutGroup,ContentSizeFitter 一起使用时,动态变化时无法及时刷新更新适配界面的问题
Unity 问题 之 ScrollView ,LayoutGroup,ContentSizeFitter 一起使用时,动态变化时无法及时刷新更新适配界面的问题 目录 Unity 问题 之 ScrollView ,LayoutGroup,ContentSizeFitter 一起使用时,动态变化时无法及时刷新更新适配界面的问题 一、简单介绍…...
linux 中 C++的环境搭建以及测试工具的简单介绍
文章目录 makefleCMakegdb调试 与 coredumpValgrind 内存检测gtest 单元测试 makefile 介绍 安装 : sudo apt install make makefile 的规则: 举例说明 包括:目标文件 、 依赖文件 、 生成规则 使用 : make make clean CMake : CMake是一个…...
448. 找到所有数组中消失的数字
找到所有数组中消失的数字 描述 : 给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。 题目 : LeetCode 448. 找到所有数组中消失的数字: 448. 找…...
为何在下雪天它“失宠”了,传统雪地靴居然不适合下雪穿
随着冬至的到来,一年之中最寒冷的“三九天”正式拉开序幕。近期各地纷纷下起了大雪,在这场大雪中雪地靴似乎“失宠”了。在社交媒体上,有网友吐槽“雪地靴根本不能下雪穿”,后面有不少网友纷纷分享了自己在雪地靴上尴尬的经历&…...
第34节: Vue3 调用内联处理程序中的方法
在UniApp中使用Vue3框架时,你可以在模板中直接调用组件内联处理程序中的方法。以下是一个示例: <template> <view> <button click"handleClick">Click me</button> <p>{{ message }}</p> </view&…...
JavaScript--明明白白Promise (Park One)
明明白白Promise (Park One) Promise是一种用于处理异步操作的特殊对象。它代表了一个尚未完成但最终会完成的操作,并可以在操作完成后返回结果或错误。 Promise有三种状态:pending(进行中)、fulfilled(已完成&#…...
el-form与el-upload结合上传带附件的表单数据(后端篇)
1.写在之前 本文采用Spring Boot MinIO MySQLMybatis Plus技术栈,参考ruoyi-vue-pro项目。 前端实现请看本篇文章el-form与el-upload结合上传带附件的表单数据(前端篇)-CSDN博客。 2.需求描述 在OA办公系统中,流程表单申请人…...
postMessage——不同源的网页直接通过localStorage/sessionStorage/Cookies——技能提升
最近遇到一个问题,就是不同源的两个网页之间进行localstorage或者cookie的共享。 上周其实遇到过一次,觉得麻烦就让后端换了种方式处理了,昨天又遇到了同样的问题。 使用场景 比如从网页A通过iframe跳转到网页B,而且这两个网页…...
上市公司-绿色投资者数据集(2000-2022)
上市公司-绿色投资者数据(2000-2022年)是一份涵盖了过去二十多年中国上市公司绿色投资情况的详细数据集。该数据集包括了各上市公司的股票代码、年份、会计年度、股票简称,以及STPT(特殊处理股票的标识),行…...
3 pandas之dataframe
定义 DataFrame是一个二维数据结构,即数据以行和列的方式以表格形式对齐。 DataFrame特点: 存在不同类型的列大小可变带有标签的轴可对列和行进行算数运算 构造函数 pandas.DataFrame( data, index, columns, dtype, copy)参数解释: 序号…...
vue-内网,离线使用百度地图(地图瓦片图下载静态资源展示定位)
前言 最近发现很多小伙伴都在问内网怎么使用百度地图,或者是断网情况下能使用百度地图吗 后面经过一番研究,主要难点是,正常情况下我们是访问公网百度图片,数据,才能使用 内网时访问不了百度地图资源时就会使用不了&…...
OpenFeign 万字教程详解
OpenFeign 万字教程详解 目录 一、概述 1.1.OpenFeign是什么?1.2.OpenFeign能干什么1.3.OpenFeign和Feign的区别1.4.FeignClient 二、OpenFeign使用 2.1.OpenFeign 常规远程调用2.2.OpenFeign 微服务使用步骤2.3.OpenFeign 超时控制2.4.OpenFeign 日志打印2.5.O…...
全自动双轴晶圆划片机:半导体制造的关键利器
随着科技的飞速发展,半导体行业正以前所未有的速度向前迈进。在这个过程中,全自动双轴晶圆划片机作为一种重要的设备,在半导体晶圆、集成电路、QFN、发光二极管、miniLED、太阳能电池、电子基片等材料的划切过程中发挥着举足轻重的作用。 全自…...
Android Studio 安装和使用
前些天,打开了几年前的一个Android Studio app项目,使用安卓虚拟机仿真app崩溃,怀疑是不是中间升级过Android Studio导致异常的,马上脑子一热卸载了,结果上次踩过的坑,一个没少又踩一次,谨以此文…...
【已解决】Java中,判断:集合中是否包含指定元素(模糊匹配)比如权限中的user:list或者是user:*这种判断
背景描述 在工作中,有时候,我们需要对list中是否包含了指定元素进行判断,但是,有时候又需要支持模糊匹配,这个时候怎么办呢? 比如权限,我们知道,权限不仅可以配置完整的路径&#…...
【基于激光雷达的路沿检测用于自动驾驶的真值标注】
文章目录 概要主要贡献内容概述实验小结 概要 论文地址:https://arxiv.org/pdf/2312.00534.pdf 路沿检测在自动驾驶中扮演着重要的角色,因为它能够帮助车辆感知道可行驶区域和不可行驶区域。为了开发和验证自动驾驶功能,标注的数据是必不可…...
【Spring实战】配置多数据源
文章目录 1. 配置数据源信息2. 创建第一个数据源3. 创建第二个数据源4. 创建启动类及查询方法5. 启动服务6. 创建表及做数据7. 查询验证8. 详细代码总结 通过上一节的介绍,我们已经知道了如何使用 Spring 进行数据源的配置以及应用。在一些复杂的应用中,…...
DevOps系列文章 : 使用dpkg命令打deb包
创建一个打包的目录,类似rpmbuild,这里创建了目录deb_build mkdir deb_build目标 我有一个hello的二进制文件hello和源码hello.c, 准备安装到/opt/helloworld目录中 步骤 在deb_build目录创建一个文件夹用于存放我的安装文件 mkdir helloworld在he…...
linux sed命令操作大全
经常使用,但有些总记不全,有时候经常查找,这次全部捋清楚做备忘,有需要的小伙伴欢迎收藏起来哦! 查、增、改、删一应俱全,非常详细! 目录 一、查看 查看第2行 查看第2行到第3行 查看第1行、…...
Vue2+Vue3组件间通信方式汇总(3)------$bus
组件间通信方式是前端必不可少的知识点,前端开发经常会遇到组件间通信的情况,而且也是前端开发面试常问的知识点之一。接下来开始组件间通信方式第三弹------$bus,并讲讲分别在Vue2、Vue3中的表现。 Vue2Vue3组件间通信方式汇总(1)…...
前端基础location的使用
概念 获取当前页面的地址信息,还可以修改某些属性,实现页面跳转和刷新等。 样例展示 window.location 含义.originURL 基础地址,包括协议名、域名和端口号.protocol协议 (http: 或 https:).host域名端口号.hostname域名.port端口号.pathname路…...
Android JNI入门到基础
一、JNI项目创建 AS创建项目时选择NativeC 会创建一个基本的JNI项目 MainActivity中写java层的native方法 具体实现在cpp文件中 native-lib.cpp #include <jni.h> #include <string>extern "C" JNIEXPORT jstring JNICALL Java_com_cn_techvision_j…...
60.乐理基础-打拍子-V字打拍法
前置内容: 文字版 https://note.youdao.com/s/6FSSvGBf (顺序参考:下方的视频版里面目录顺序) 视频版 【四川音乐学院作曲硕士】教你零基础自学乐理保姆级教学-学习视频教程-腾讯课堂 文字版还有下图红框中三个专栏里的内容&a…...
列表对象的时间进行中文格式化处理
在黑马的项目学习中,如何将前端页面时间显示成2023年12月21日 06:23:23中文形式。 如果你想使用中文格式化日期,你可以将 en-US 更改为 zh-CN,以使用中文语言环境。以下是修改后的代码: result.data.items.forEach(item > {//…...
vi和vim的区别
目录 一、前言 二、vi/vim 的介绍 三、Vi/Vim 常见指令 四、vi和vim的区别 一、前言 写这篇文章的目的,是为了告诉大家我们如果要在终端下对文本进行编辑和修改可以使用vim编辑器。 Ubuntu 自带了 VI 编辑器,但是 VI 编辑器对于习惯了 Windows 下进…...
淘宝联盟怎么做自已的网站/seo 资料包怎么获得
用UML表示树型的数据时,很特别,所以在这里特别画一画。 注意,因为UML的关联本身就代表了一个引用,所以不需要再在类图中再写出来(如Parent, Childs).转载于:https://www.cnblogs.com/wonderKK/archive/2012/03/07/2382…...
广州网站建设设计哪家好/新品牌推广方案
在HTML中设置email链接的方法:首先在HTML中添加一个a标签;然后给a标签的“href”属性提供一个email地址即可,语法格式“email邮件”。本教程操作环境:windows7系统、HTML5版、Dell G3电脑。HTML 标签标签定义超链接,用…...
昆山广告公司/如何做seo整站优化
摘 要: 多位点序列分型(MLST)是一种基于核酸序列测定的细菌分型方法,通过PCR扩增多个管家基因内部片段,测定其序列,分析菌株的变异,从而进行分型。MLST被广泛应用于病原菌、环境菌和真核生物中。…...
容桂做网站/seo包年优化
1 在windows下运行python程序1)从DOS命令行运行python脚本用python解释器来执行python脚本,在windows下面python解释器是python.exe,我的python文件安装在D:\Python27,在这个目录下可以看到python解释器。完整的命令应该是:python解释器 .p…...
济源网站开发/哈尔滨企业网站seo
首先,我们要知道autoLink和linksClickable是干什么用的。 autoLink当中有五个属性值:分别是phone、email、map、web、all和none,前四个分别是自动识别电话号码、邮箱、地址和网址,而第五个是识别前四个的全部,none是不…...
网络营销与策划实训/长沙网站优化推广方案
结果为: [2,3] 和 [2] array.splice(start[, deleteCount[, item1[, item2[, …]]]]) splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。 start: 指定修改的开始位置(从0计数) i…...