C++入门(以c为基础)——学习笔记2

news2024/11/18 12:21:25

1.引用

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空

间。在语法层面,我们认为它和它引用的变量共用同一块内存空间

可以取多个别名,也可以给别名取别名。

                                         

b/c/d本质都是别名,对d进行一个++

对于符号&,用其定义时就是引用,其他时候就是取地址

从此,改变一个变量不需要传地址,而可以在形参处定义别名,达到类似指针的效果。

“经典的错误,标准的零分”

为什么a的值还是没有改变?

    尽管传入的是别名 ,但是函数接受的参数依然是个数值,是实参的拷贝。应当在形参处建立引用,这样才能真正修改我们希望修改的变量。

这样就成功改变a的值了。

结论:形参是引用,则通过形参就能改变实参,不需要传更高级的指针。

引用中需要注意的细节: 

1.1引用在定义时必须先初始化

引用在定义时必须已经初始化(不能先取绰号,再找谁合适这个绰号)

一个引用可以有多个变量,就如上文的a b c d

引用一旦引用一个实体,就不能再改变

可见,不是让y变成z的别名,而是通过y,将z的值赋值给y和x

1.2引用中的权限问题

 存在的问题:权限的放大

m是只读的,当n变成m的别名后,n作为int类型的变量是可读可写的。为了避免通过n修改了m这个const类型的变量(权限放大),所以不能通过编译。

这样,是权限的平移,就能通过编译了。

对一个对象(C语言中喜欢称为变量),权限可以缩小和平移,但是不能放大。

                                            

                                             

此处我可以通过y修改x,修改后z的数值也会改变(相当于z只是没有“write”的权限,z只能访问x, 并不代表这个值真真正正地锁死了)

回忆:const int*      int  const*      int* const 

const默认与其左边结合,当左边没有任何东西则与右边结合。

       换句话说,const只要在*的左边,限制的就是*p1;const在*右边,限制的就是这个指针,该指针只能指向这个空间,不能改变指向。

上文中的前两种所限制的是一样的,最后一种限制的是指针,不能进行加减法。

             

报错的原因是:p2是可读可写的,我们可以通过p2去改变p1所指向的空间。但是p1指向的空间是被锁死了的,是不能改变的,又扩大了权限,因此报错。

数值之间没有权限的概念,只有指针和引用之间有权限的概念。


类型转化中的权限问题:

不管是强制类型转化还是隐式类型转化,其底层都是通过建立一个临时变量来进行转化。

我们先用double定义一个变量为12.34: 

                                                

其转化的本质是把d的整数部分取出,赋给整形类型的临时变量,再通过临时变量赋给i。

既然是这样的赋值方法,就不难理解下图为什么会报错了: 

                   

在82行代码执行时,d先将其整数部分赋值给临时变量,但是临时变量具有常性(像一个常数一样,不可被改变),而按照int& j的方法接受该临时变量后,j作为别名,可以通过j修改该临时变量,这是不被允许的。

但如果我给这个变量定义为“只读”类型,也就是const int& k=d; 

权限没有被放大,就合规了。 

                                                所有的表达式运算也会产生临时变量

int x=1;
int y=2;
x+y;

 没有用变量接受x+y,但是x+y还是会进行计算,计算出的结果会放进临时变量。

同理,有变量接受x+y时也一样,x+y的值放入临时变量,所以r2前面必须加const(只读)才能保证不越界。

                                          

1.3传参和传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直
接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效
率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

                                              

直接传值会拷贝整个变量(形参是实参的copy),传参效率弱于引用传参。 

再利用一个测试函数:

(将传值执行10000次,再将传引用执行10000次,0表示其所消耗的时间是小于1ms的) 

1.4从底层看引用

我们在语法层面认为:别名不开空间,存地址的变量(指针)是需要开辟空间的。

但是在汇编层面:

通过底层可知,定义指针p和引用b的汇编代码是一样的。

不过在日常的语法层面,我们依然认为引用不开空间,指针变量要开空间。

1.5指针和引用的区别

1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
2. 引用 在定义时 必须初始化 ,指针没有要求
3. 引用 在初始化时引用一个实体后,就 不能再引用其他实体 ,而指针可以在任何时候指向任       何一个同类型实体
4. 没有 NULL 引用 ,但有 NULL 指针
5. sizeof 中含义不同 引用 结果为 引用类型的大小 ,但 指针 始终是 地址空间所占字节个数 (32 位平台下占4 个字节 )
6. 引用自加即引用的实体增加 1 ,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同, 指针需要显式解引用,引用编译器自己处理
9. 引用比指针使用起来相对更安全

不过对于第四点,可以单独说明一下: 

                                      

不是说没有NULL引用吗?

结合底层思考为什么没有报错

   

 通过观察汇编,我们可以发现,并没有发生解引用这一步骤。

因为其本质是和指针一样的汇编代码,所以并没有发生报错。

cpp的引用为什么不能替代指针

如:链表:

引用不能改变指向,如果用引用的方法存下下一个节点,当你想改变链接方式时,如何处理?

所以next必须使用指针。这单纯的是语法设计的原因,因为本贾尼是按照c为基础设计的,并没有想过要完全替代C语言。在Java中,引用就是可改变的,因此java没有指针。

2.内联函数

对于一些小型的、会大量重复调用的函数,如(Swap,Add等)。不停的建立函数栈帧性价比太低,C语言使用含参数的宏来解决这个问题。

宏没有栈帧消耗,但是容易出语法问题:复杂、没有类型检查、无法调试

cpp虽然兼容c的所有用法,但是cpp更倾向于使用内联函数(inline修饰):

inline 修饰 的函数叫做内联函数, 编译时 C++ 编译器会在 调用内联函数的地方展开 ,没有函数调 用建立栈帧的开销,内联函数提升程序运行的效率。本质是一种空间换时间的做法。

用inline修饰函数

                     

注意:在debug模式下,为了调试方便,依然会执行call语句,像以前的函数一样建立栈帧。

没有执行call语句,也就是没有按照函数去调用,而是直接展开。

内联函数的特点:

编译器并没有把是否展开的权利完全释放给你,而是会自己选择是否展开。

当函数中的语句过多时,就不会展开

inline对于编译器只是一种建议,编译器会自己决定是否展开(如递归等就一定不会展开)


为什么有的函数语句过多时不会展开?

大函数展开的缺点:

若我们要对一个100行的代码调用10000次:

导致编译出的可执行程序变大。可执行程序大了是一件很麻烦的事情。


最后,内联函数不能声明和定义相分离 

因为内联函数是直接展开的,没有函数的地址,在链接过程中是找不到的。

其本质就是一个小型功能直接展开。

3.auto

随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:
1. 类型难于拼写
2. 含义不明确导致容易出错
                                        (只不过在目前的学习中还不存在这样的问题)

根据赋值的内容,自动识别i的类型。

当然,typedef有类似的功能,但是typedef有时候会有些问题:

 

pstring p1 与 char* const p1是一个意思,p1 作为一个被const的变量,也具有常性,必须初始化,所以此处报错。


​​​​​​​tips:typeid可以用来查看变量的类型名:

typeid(a).name();

auto修饰的限定 

auto可以根据后面的内容进行赋值内容的条件限制。


     规定:auto不能直接用来声明数组

                    

4.基于范围的for循环

基于auto的用法,cpp抄了python的作业,使用自动循环:

for循环迭代的范围必须是确定的

for (auto e: array){
    
    e/=2;
}

auto可以改成具体的类型(int、double)等都可以,只要匹配就行

但是遍历方式是写死了的,只能从数组首到数组尾遍历。

但是传参进入的数组不能使用范围for

数组的传参本质是传入数组首元素地址,会退化。(c/cpp追求效率,在语言层进行了优化,传的是首元素地址)

                               

而针对一个数组首元素地址,该数组循环迭代的范围是不确定的,所以不能执行。

5.nullptr和NULL

cpp的设计缺陷:  将NULL作为一个宏,代表0,而不是之前的空指针。因此,cpp中的NULL会被当作整形的int而不是空指针

所以,引入了关键字nullptr

主函数中:第一个f调用第一个函数,第二个f也调用第一个函数,第三个f调用第二个函数,第四个函数调用第二个函数。

nullptr作为关键字,是不需要包含任何头文件的

6.小结

本篇中多为零碎的c过渡到cpp的语法知识,先进行铺垫和了解,在之后会有具体而详细的使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1571021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QA测试开发工程师面试题满分问答3: python的深拷贝和浅拷贝问题

在 Python 中,深拷贝(deep copy)和浅拷贝(shallow copy)是用于创建对象副本的两种不同方式。 浅拷贝是创建一个新的对象,该对象与原始对象的内容相同(包括内部嵌套对象的引用)&…

SSM框架学习——了解Spring与Eclipse创建Maven项目

了解Spring 什么是Spring Spirng是分层的JavaSE/EE全栈轻量级开源框架,以控制反转IoC和面向切面编程AOP为内核,使用基本的JavaBean来完成EJB的工作。 Spring框架采用分层架构,它的一些列功能被分为若干个模块。 上图中的红色背景模块为本…

提示工程概要

提示工程 1. 两大原则 原则 1&#xff1a;编写清晰具体的说明 使用分隔符 三引号&#xff1a;“”"三个反引号&#xff1a;三个破折号&#xff1a;—尖括号&#xff1a;<>XML标签&#xff1a; 要求结构化输出 HTMLJSONXMLPython字典 检查条件是否满足 检查执行…

C++ 类和对象(初篇)

类的引入 C语言中&#xff0c;结构体中只能定义变量&#xff0c;在C中&#xff0c;结构体内不仅可以定义变量&#xff0c;也可以定义函数。 而为了区分C和C我们将结构体重新命名成class去定义 类的定义 标准格式&#xff1a; class className {// 类体&#xff1a;由成员函…

linux安装和使用Rancher

linux安装和使用Rancher Rancher介绍请看如下博客 arm架构安装Rancher并导入k8s集群解决Error: no objects passed to apply 华为云arm架构安装k8s(kubernetes) linux下安装Rancher Rancher部署监控k8s集群状态等,比Dashboard插件强大 提前安装好K8S 在master上执行#如果…

学习心得1

这时我第一次更学习心得&#xff01;不足的在评论区指教。 首先先来分享一下&#xff0c;刷一维数组题目的方法。 仔细读题&#xff0c;不会做的题目先完成输入输出。不要干等着着急&#xff0c;就跳到下一题。如果使用的时oj&#xff0c;那就没有题解但是使用洛谷、LeetCood…

【热门话题】计算机视觉入门:探索数字世界中的“视觉智能”

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 计算机视觉入门&#xff1a;探索数字世界中的“视觉智能”摘要正文一、计算机视…

MATLAB——知识点备忘

最近在攻略ADC建模相关方面&#xff0c;由好多零碎的知识点&#xff0c;这里写个备忘录。 Matlab 判断一个数是否为整数 1. isinteger 函数 MATLAB中&#xff0c;可以使用 isinteger 函数来判断一个数是否为整数&#xff0c;例如&#xff1a;要判断x是否为整数可以采用以下代…

链式二叉树经典OJ题目(二)

目录 结构体及头文件&#xff1a; 1.二叉树的前序遍历 题目描述&#xff1a; 思路分析&#xff1a; 源码&#xff1a; 2.二叉树的翻转 题目描述&#xff1a; 思路分析&#xff1a; 源码&#xff1a; 3.另一颗子树 题目描述&#xff1a; 思路分析&#xff1a; 源码&…

蓝桥杯单片机真题实践篇

这里就不完全写思路过程代码什么的&#xff0c;这一篇文章就写我在训练真题中遇到的过程。 &#xff08;呜呜呜&#xff0c;时间不够辣&#xff0c;能做多少算多少吧....&#xff09; 十三届省赛题 问题1&#xff1a;数码管的数字消影不明显 &#xff08;参考&#xff1a;蓝…

Splunk Attack Range:一款针对Splunk安全的模拟测试环境创建工具

关于Splunk Attack Range Splunk Attack Range是一款针对Splunk安全的模拟测试环境创建工具&#xff0c;该工具完全开源&#xff0c;目前由Splunk威胁研究团队负责维护。 该工具能够帮助广大研究人员构建模拟攻击测试所用的本地或云端环境&#xff0c;并将数据转发至Splunk实例…

ARM架构学习笔记1-寄存器

ARM内部寄存器 有R0-R1516个寄存器 R0-R12通用目的寄存器Program status Register&#xff1a;程序状态寄存器 &#xff0c;用来保存某些状态的值保存:m3/m4架构保存在xPSR&#xff0c;coretex-A7架构保存在CPSR中XPSR是程序状态寄存器 MRS命令&#xff1a;表示Move to Regis…

Tuxera NTFS for Mac2023绿色免费版 免费的ntfs for mac 免费读写硬盘U盘工具

Tuxera NTFS 2023 Mac免费版是款适合Mac用户使用的磁盘读写工具。Tuxera NTFS 2023 Mac可以很好的帮助用户在Mac上打开、编辑、复制、移动或删除存储在Windows NTFS格式的USB驱动器上的文件。并且Tuxera NTFS 2023 Mac还可以无阻碍地使用各种文件系统磁盘&#xff0c;还能解决磁…

数据生成 | Matlab实现基于K-means和SVM的GMM高斯混合分布的数据生成

数据生成 | Matlab实现基于K-means和SVM的GMM高斯混合分布的数据生成 目录 数据生成 | Matlab实现基于K-means和SVM的GMM高斯混合分布的数据生成生成效果基本描述模型描述程序设计参考资料 生成效果 基本描述 1.Matlab实现基于K-means和SVM的GMM高斯混合分布的数据生成&#xf…

vivado 向 SVF 目标添加器件

向 SVF 目标添加器件 创建 SVF 目标后 &#xff0c; 可向其中添加器件以定义 SVF JTAG 器件链配置。 SVF JTAG 器件链配置应与目标硬件链相匹配 &#xff0c; 以 确保能正确执行 SVF 文件。 使用 Vivado IDE 单击“ ”按钮以向 SVF 链添加赛灵思器件或非赛灵思器件。…

法向量估计

法向量估计 1. 求解点P法向量的原理2. 法向量估计的证明3. 为什么求点P的法向量&#xff0c;需要使用以P为中心的邻域内的点&#xff1f;4. 法向量估计的应用和思考5. 权重法向量估计 1. 求解点P法向量的原理 已知有一组点 P ( p 1 , p 2 , p 3 , . . . , p n ) , p i ∈ R 3…

糖豆人打开失败或无法运行

一般就是网络不行&#xff0c;选择加速器加速就好了。 eg: (uu加速器) 一般直接点启动游戏就行。 如果提示找不到文件路径&#xff0c;或者说直接弹出steam的登录的话就是配置路径有问题。现在糖豆人已经不再steam平台了&#xff0c;应该是epic才对。 配置方法&#xff1a;…

普通人想要赚钱,就要坚持五个要点

最近都在努力搞钱&#xff0c;所以今天就围绕【持续赚钱】&#xff0c;分享一些心得体会。 普通人想要赚钱&#xff0c;就要坚持以下5点&#xff1a; 持续学习 持续破圈 持续行动 坚持长期利他 坚持长期主义 1、持续学习 要持续学习&#xff0c;做一个终身学习者。 只有保持空杯…

通用开发技能系列:Git

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 通用开发技能系列 文章&#xff0c;主要对编程通用技能Git进行学习 1.为什么使用版本控制系统 版本控制系统可以解决的问题 代码备份很重要版本控制很重要协同工作很重要责任追溯很重要 常见的版本控制系统 Gi…

【学习笔记】java项目—苍穹外卖day10

文章目录 苍穹外卖-day10课程内容1. Spring Task1.1 介绍1.2 cron表达式1.3 入门案例1.3.1 Spring Task使用步骤1.3.2 代码开发1.3.3 功能测试 2.订单状态定时处理2.1 需求分析2.2 代码开发2.3 功能测试 3. WebSocket3.1 介绍3.2 入门案例3.2.1 案例分析3.2.2 代码开发3.2.3 功…