【C++】入门基础(下)

Hi!很高兴见到你~

目录

7、引用

7.3  引用的使用(实例)

7.4  const引用

【第一分点】 

 【第二分点1】

【第二分点2】

7.5  指针和引用的关系(面试点)

8、inline

9、nullptr

Relaxing Time!

——————————《Go Solo》——————————


正文开始——

7、引用

7.3  引用的使用(实例)

//引用作参数,改变引用对象的同时改变被引用对象#include<iostream>
#include<assert.h>using namespace std;//这里rx,ry就相当于x和y的别名,不需要再传地址了
void Swap(int& rx, int& ry)
{int tmp = rx;rx = ry;ry = tmp;
} 
int main()
{int x = 0, y = 1;cout << x << " " << y << endl;Swap(x, y);cout << x << " " << y << endl;return 0;
}
//引用作参数,传值传参时要拷贝实参给形参,下面使用引用会减少拷贝提高效率
struct A
{int arr[1000]={0};
}void Func(A& aa)
{//...
}int main()
{Func(aa1);return 0;
}//不用再把实参的4000个字节传给实参,这样就提高了效率,虽然用指针也行但引用更方便
//传引用返回实例,与指针相较
#include<iostream>
#include<assert.h>using namespace std;
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;void STInit(ST& rs, int n = 4)
{rs.a = (STDataType*)malloc(n * sizeof(STDataType));rs.top = 0;rs.capacity = n;
} // 栈顶
void STPush(ST& rs, STDataType x)
{// 满了, 扩容if (rs.top == rs.capacity){printf("扩容\n");int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;} rs.a = tmp;rs.capacity = newcapacity;} rs.a[rs.top] = x;rs.top++;
}//引用
int& STTop(ST& rs)
{assert(rs.top > 0);return rs.a[rs.top-1];
} //指针
int* STTop(ST& rs)
{assert(rs.top > 0);return &(rs.a[rs.top - 1]);
}int main()
{// 调⽤全局的ST st1;STInit(st1);STPush(st1, 1);STPush(st1, 2);cout << STTop(st1) << endl;//修改栈顶数据//引用STTop(st1) += 10;//指针*(STTop(st1)) += 100;//相比之下,引用使用更方便cout << STTop(st1) << endl;return 0;
}

【细节详解】 

#include<iostream>
using namespace std;//不是所有情况都可以用传引用返回,举例
//Func函数用传引用返回,但是出了Func函数ret这个局部变量就销毁了,如果继续引用,就会越界
int& Func()
{int ret = 20;//...return ret;
}
int main()
{//此处返回的是ret的别名,但是ret已经被销毁了,越界了Func() += 10;//越界不一定会报错int arr[10];//越界读(打印等不修改)不报错cout << arr[10] << endl;cout << arr[11] << endl;cout << arr[12] << endl;//越界写(修改)不一定报错,一般是抽查,在数组后面设置两个值,若值被改变,说明越界arr[10] = 100;return 0;
}

7.4  const引用

  • 可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大。
  • 需要注意的是类似 int& rb=a*3;double d=12.34;int& rd=d;这样的一些场景下a*3的结果保存在临时对象中,int& rd=d也是类似,在类型转换中会产生临时对象存储中间值也就是说,rb和rd引用的都是临时对象,而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以。
  • 所谓临时对象就是编译器需要一个空间暂存表达式的求值结果时创建的一个未命名的对象,C++中把这个未命名对象叫做临时对象。

【第一分点】 

//可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大。
int main()
{const int a = 10;//编译报错:error C2440:“初始化”: 无法从“const int”转换为“int &”//这里的引用是对a权限的放大,const修饰后a只能读不能写(修改)int& ra = a;//针对上面的问题应该这样改,用const引用const int& ra = a;//error C3892 : “ra”: 不能给常量赋值,此处ra只许读不许写ra++;//这里的引用是对b访问权限的缩小,//const也可以引用普通对象int b=100;const int& rb=b;//编译报错:error C3892:“rb”:不能给常量赋值,此处rb和b指向的是同一块空间,rb的权限缩小不影响breturn 0;
}

见下图详解:

 【第二分点1】

int main()
{//需要注意的是类似 int& rb=a*3;double d=12.34;int& rd=d;//这样的一些场景下a*3的结果保存在临时对象中,int& rd=d也是类似,//在类型转换中会产生临时对象存储中间值,也就是说,rb和rd引用的都是临时对象,//而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以。int a = 10;//int& rb = a * 3;const int& ra = a * 3;/*double d = 13.14;int rd = d;*/double d = 13.14;int& rd = d;//这里划红线并非是int类型引用double类型的问题,而是d先存储在临时变量里面,//所以rb引用的是一个临时变量,这个临时变量具有常性,就像被const修饰一样,//这里就触发了权限的放大const int& rd = d;return 0;
}

 见下图详解:

【第二分点2】

7.5  指针和引用的关系(面试点)

C++中指针和引用就像两个性格迥异的亲兄弟,指针是哥哥,引用是弟弟,在实践中他们相辅相成,功能具有重叠性。但是各有自己的特点,互相不可替代。

  • 语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量的地址,要开空间。
  • 引用在定义时必须初始化,指针建议初始化,但语法上不是必须的。
  • 引用在初始化时引用一个对象后,就不能在引用其他对象,而指针可以不断地改变指向对象。
  • 引用可以直接访问引用对象,指针需要解引用才能才能访问指向对象。
  • sizeof 中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占的字节个数(32位平台下占4个字节,64位平台下占8个字节)。
  • 指针很容易出现空指针和野指针的情况,引用很少出现,引用使用起来相对安全一些。
//sizeof 中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占的字节个数(32位平台下占4个字节,64位平台下占8个字节)。#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;int main()
{int a = 0;int& ra = a;int* pta = &a;cout << sizeof(ra) << endl;cout << sizeof(pta) << endl;return 0;
}
//指针很容易出现空指针和野指针的情况,引用很少出现,引用使用起来相对安全一些。
//这里ret就是野引用#include<iostream>
using namespace std;//不是所有情况都可以用传引用返回,举例见下
//Func函数用传引用返回,但是出了Func函数ret这个局部变量就销毁了,如果继续引用,就会越界
int& Func()
{int ret = 20;//...return ret;
}
int main()
{//此处返回的是ret的别名,但是ret已经被销毁了,越界了Func() += 10;//越界不一定会报错int arr[10];//越界读(打印等不修改)不报错cout << arr[10] << endl;cout << arr[11] << endl;cout << arr[12] << endl;//越界写(修改)不一定报错,一般是抽查,在数组后面设置两个值,若值被改变,说明越界arr[10] = 100;return 0;
}

8、inline

  • 用 inline 修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧,提高效率。
  • inline对于编译器而言只是一个建议,也就是说,加了inline编译器也可以选择在调用的地方不展开,不同的编译器就关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适用于频繁地调用短小的函数,对于递归函数,代码相对多一些的函数,加上inline也会被编译器忽略。
  • C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错,切不方便调试,C++设计inline目的就是为了替代C的宏函数。
  • VS编译器debug版本下面默认是不展开inline的,这样方便调试,debug版本想展开需要设置以下两个地方。
  • inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现错误。 

inline对于相对多一些的函数,为什么加上inline也会被编译器忽略呢?

 假如Add函数有100行指令,有10000个地方调用

Add展开,要10000*100行指令;

Add不展开,建立栈帧,但是只要10000*1+100行指令。

可以看作是编译器的一个防御策略。

#include<iostream>
using namespace std;
// 实现⼀个ADD宏函数的常⻅问题
//#define ADD(int a, int b) return a + b;
//#define ADD(a, b) a + b;
//#define ADD(a, b) (a + b)// 正确的宏实现
#define ADD(a, b) ((a) + (b))
// 为什么不能加分号?
// 为什么要加外⾯的括号?
// 为什么要加⾥⾯的括号?int main()
{//宏的本质相当于替换// 为什么不能加分号?int ret = ADD(1, 2);cout << ADD(1, 2) << endl;//如果加分号,就变成了下面这样,报错cout << ADD(1, 2); << endl;// 为什么要加外⾯的括号?cout << ADD(1, 2)*5 << endl;cout << (a) + (b)*5 << endl;// 为什么要加⾥⾯的括号?int x = 1, y = 2;ADD(x & y, x | y); // -> (x&y+x|y)//这样就变成了y+x先运算,+的优先级更高,加减乘除的优先级都是偏高的,位运算的优先级都是偏低的return 0;
}
#include<iostream>
using namespace std;
//没有宏函数的坑,也不用建立栈帧,提效
inline int Add(int x, int y)
{int ret = x + y;ret += 1;ret += 1;ret += 1;return ret;
} int main()
{// 可以通过汇编观察程序是否展开// 有call Add语句就是没有展开,没有就是展开了,但Add函数较长,就不展开了,inline对编译器是一个 //建议,最终决定权在编译器int ret = Add(1, 2);cout << Add(1, 2) * 5 << endl;return 0;
}

9、nullptr

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看见如下代码:

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
  • C++中NULL可能被定义为字面常量0,或者C中被定义为无类型指针(void*)的常量。不论采用何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,本想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义为0,调用了f(int*),因此与程序的初衷相悖。f(void*)NULL;调用会报错。
  • C++11中引入nulltptr,nullptr是一个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式的转换为指针类型,而不能被转换成整数类型。
#include<iostream>
using namespace std;void f(int x)
{cout << "f(int x)" << endl;
} void f(int* ptr)
{cout << "f(int* ptr)" << endl;
} int main()
{f(0);// 本想通过f(NULL)调⽤指针版本的f(int*)函数,但是由于NULL被定义成0,调⽤了f(intx),因此与程序        //的初衷相悖。f(NULL);f((int*)NULL);// 编译报错:error C2665: “f”: 2 个重载中没有⼀个可以转换所有参数类型// f((void*)NULL);f(nullptr);return 0;
}

完——


Relaxing Time!

                   ——————————《Go Solo》——————————

  Go Solo_Zwette、Tom Rosenthal_高音质在线试听_Go Solo歌词|歌曲下载_酷狗音乐

至此结束!

我是云边有个稻草人

期待与你的下一次相遇——

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

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

相关文章

Mysql(二) - 约束, 进阶查询

目录 一.约束 1.not null 2.unique 3.default 4.primary key 5. foreign key 6.check 7. 综合使用 二.进阶查询 1.新增(插入查询的结果) 2.聚合查询 a.聚合函数 b.使用 3.分组查询 4.联合查询 a.内连接 b.外连接 c.自连接 d.子查询 5.合并查询 三.总结 一…

基于SpringBoot的招生宣传管理系统【附源码】

基于SpringBoot的招生宣传管理系统&#xff08;源码L文说明文档&#xff09; 目录 4 系统设计 4.1 系统概述 4.2系统功能结构设计 4.3数据库设计 4.3.1数据库E-R图设计 4.3.2 数据库表结构设计 5 系统实现 5.1管理员功能介绍 5.1.1管理员登录 …

Ubuntu22.04系统安装opencv步骤简述及问题解决方法

前言 opencv是一个功能强大、开源且跨平台的计算机视觉库&#xff0c;适用于多种编程语言和操作系统&#xff0c;能够帮助开发者构建各种视觉项目。其模块众多&#xff0c;提供了诸多功能&#xff0c;能够进行图像处理、视频处理等等。比如&#xff1a;Highgui模块提供图像用户…

Python 解析 JSON 数据

1、有如下 JSON 数据&#xff0c;存放在 data.json 文件&#xff1a; [{"id":1, "name": "小王", "gender": "male", "score": 96.8}, {"id":2, "name": "小婷", "gender&qu…

Python 课程12-Python 自动化应用

前言 Python 自动化应用 可以帮助开发者节省时间和精力&#xff0c;将重复性、手动操作变为自动化脚本。例如&#xff0c;Python 可以用于自动化处理文件、邮件、生成报表&#xff0c;甚至可以控制浏览器执行复杂的网页操作任务。借助 Python 的强大库和工具&#xff0c;可以轻…

python学习——对无人机影像有RGB转换到HSV

问题描述 最近需要对无人机影像中绿色植被信息进行提取&#xff0c;查看相关论文&#xff0c;发现用的比较多的就是HSV色彩转换方法&#xff0c;动手实践一下。 解决思路 #mermaid-svg-5ejGodIusPv6zFVS {font-family:"trebuchet ms",verdana,arial,sans-serif;fon…

浪潮信息首推3秒智能控温!告别服务器开机噪音

在当前的数据中心运维实践中&#xff0c;运维人员在部署服务器时常被“飞机起飞”般的开机噪音所困扰。服务器刚刚接通电源&#xff0c;其内部元件尚处于预热待命状态&#xff0c;而风扇却已全速运转&#xff0c;这不仅加剧了噪音污染&#xff0c;还拖慢了启动速度&#xff0c;…

了解华为云容器引擎(Cloud Container Engine)

1.什么是云容器引擎&#xff1f; 云容器引擎&#xff08;Cloud Container Engine&#xff0c;简称CCE&#xff09;提供高度可扩展的、高性能的企业级Kubernetes集群。借助云容器引擎&#xff0c;您可以在华为云上轻松部署、管理和扩展容器化应用程序。云容器引擎是一个企业级的…

【Python机器学习】循环神经网络(RNN)——超参数

几乎所有模型都可以根据数据和样本进行调整&#xff0c;它们都有各自的优势和相应的利弊权衡方式。寻找最优超参数集通常是一个棘手的问题&#xff0c;但是人类的直觉和经验可以为我们提供解决问题的方法。比如之前的例子&#xff1a; #设置任意输入序列的最大长度 maxlen100 …

鸿蒙 ArkUI组件二

ArkUI组件&#xff08;续&#xff09; 文本组件 在HarmonyOS中&#xff0c;Text/Span组件是文本控件中的一个关键部分。Text控件可以用来显示文本内容&#xff0c;而Span只能作为Text组件的子组件显示文本内容。 Text/Span组件的用法非常简单和直观。我们可以通过Text组件来显…

多模态大语言模型综述(中)-算法实用指南

本文是Multimodal Large Language Models: A Survey的译文之算法实用指南部分。 上&#xff1a;摘要、概念与技术要点实用指南中&#xff1a;算法实用指南(本文)下: 任务的实用指南(应用)、挑战等 原始信息 标题: Multimodal Large Language Models: A Survey译文: 多模态大…

拓扑排序算法

拓扑排序算法 上图意思为在我想要完成C7这件事之前我必须先完成事件C1&#xff0c;在完成C5这件事之前我必须先完成事件C6和C3.由图可以提看出拓扑序列是不唯一的。 有向图拓扑排序算法基本步骤&#xff1a; 1.从图中选择一一个入入度为0的顶点, 输出该顶点; 2.从图中删除该…

MutationObserver详解+案例——深入理解 JavaScript 中的 MutationObserver:原理与实战案例

目录 深入理解 JavaScript 中的 MutationObserver&#xff1a;原理与实战案例 一、MutationObserver 简介 二、MutationObserver 的工作原理 1、基本用法 2、observe 方法的配置项 三、实战案例 案例 1&#xff1a;监控动态内容加载 案例 2&#xff1a;监控属性变化 案…

springboot 项目获取 yaml/yml (或 properties)配置文件信息

文章目录 springboot 项目获取配置文件信息前言1、 Autowired 注入 Environment类2、基础用法&#xff0c;使用Value注解直接注入配置信息3、进阶方法&#xff08;推荐使用&#xff09;拓展&#xff1a;springboot 集成配置中心 - 以 Apollo 为例 springboot 项目获取配置文件信…

通信工程学习:什么是接入网(AN)中的TF传送功能

接入网&#xff08;AN&#xff09;中的TF传送功能 在通信工程中&#xff0c;TF&#xff08;Transfer Function&#xff09;传送功能是指为接入网&#xff08;AN&#xff09;不同位置之间提供通道和传输介质&#xff0c;以实现数据的有效传输。以下是关于TF传送功能的详细解释&a…

PMP--一模--解题--91-100

文章目录 13.干系人管理91、 [单选] 在项目执行期间&#xff0c;一名外部干系人反对一项重大范围变更。除非重新评估干系人的决定&#xff0c;否则项目进展将受到影响。项目经理下一步该怎么做&#xff1f; 5.范围管理92、 [单选] 一客户给你一复杂项目的采购工作说明书&#x…

配置全新服务器深度学习一套流程

目录 1.安装anaconda2.配置cuda3.配置cudnn4.配置新的pytorch环境5.安装rdkit包6.小问题记录 1.安装anaconda 直接参考视频 总结&#xff1a; 1.下载anaconda安装包&#xff0c;尽量不下载最新的版本 2.bash 对应安装包&#xff0c;一直回车&#xff0c;yes 3.配置环境vim ~/.…

实战千问2大模型第三天——Qwen2-VL-7B(多模态)视频检测和批处理代码测试

画面描述:这个视频中,一位穿着蓝色西装的女性站在室内,背景中可以看到一些装饰品和植物。她双手交叉放在身前,面带微笑,似乎在进行一场演讲或主持活动。她的服装整洁,显得非常专业和自信。 一、简介 阿里通义千问开源新一代视觉语言模型Qwen2-VL。其中,Qwen2-VL-72B在大…

在k8s中,客户端访问服务的链路流程,ingress--->service--->deployment--->pod--->container

ingress是一个API资源。 其核心作用是nginx网页服务器。 当客户端访问服务器不同的url时, 用不同的location提供服务。 在k8s之外&#xff0c;nginx的配置一般如下&#xff1a; http {server {listen 80;server_name localhost;location / {root html; …

鸿蒙开发入门day19-使用NDK接口构建UI(一)

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;还请三连支持一波哇ヾ(&#xff20;^∇^&#xff20;)ノ&#xff09; 目录 NDK接口概述 整体架构 开发流程 接入ArkTS页面 占位组件 NDK组…