C++入门2

目录

前言:

引用

引用特性:

常引用:

使用场景:

1. 做参数

2. 做返回值

3.引用做返回值(方便读写返回变量)

传值、传引用效率比较:

引用和指针的区别:

内联函数

auto关键字(C++11)

auto的使用细则:

1.auto与指针和引用结合起来使用

2. 在同一行定义多个变量

auto不能推导的场景:

1. auto不能作为函数的参数

2. auto不能直接用来声明数组

3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法

4. auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等进行配合使用。 

指针空值nullptr(C++11)

C++98中的指针空值


前言:

 从上一章开始我们就正式将要开启C++的大门,本章承接上一章介绍C++入门所需要掌握和学习的知识,方便我们彻底打开C++的大门。 上一章的博客:C++入门-CSDN博客

引用

引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空
间,它和它引用的变量 共用同一块内存空间。
比如我们一提到“花和尚”我们就会自然联想到水浒传里的鲁智深,“花和尚”就是鲁智深的别名,也就是鲁智深的外号。

引用的使用方式:类型& 引用变量名(对象名) = 引用实体;

void TestRef()
{int a = 10;int& ra = a;//<====定义引用类型printf("%p\n", &a);printf("%p\n", &ra);
}

引用类型必须和引用实体同种类型的 

引用特性:

1. 引用在 定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体
void TestRef()
{int a = 10;// int& ra;   // 该条语句编译时会出错int& ra = a;int& rra = a;printf("%p %p %p\n", &a, &ra, &rra);  //地址相同
}

常引用:

void TestConstRef()
{const int a = 10;//int& ra = a;   // 该语句编译时会出错,a为常量const int& ra = a;// int& b = 10; // 该语句编译时会出错,b为常量const int& b = 10;double d = 12.34;//int& rd = d; // 该语句编译时会出错,类型不同const int& rd = d;
}

使用场景:

1. 做参数

void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}

2. 做返回值

int& Count()
{static int n = 0;n++;// ...return n;
}

3.引用做返回值(方便读写返回变量)


int& Add(int a, int b)
{int c = a + b;return c;
}int main()
{int& ret = Add(1, 2);Add(3, 4);cout << "Add(1, 2) is :"<< ret <<endl;return 0;
}
注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用
引用返回,如果已经还给系统了,则必须使用传值返回。

 上述代码的输出结果为Add(1, 2) is : 7

 简单来说不传引用返回就是在Add函数的栈帧中存在c这个局部变量用来接收a+b的,函数结束前是要return c的,而这个时候c的内容会被复制到寄存器里面,再由寄存器把返回值赋值到main函数中接收返回值的变量。

而传引用返回就是将Add函数栈帧里的c这个地址上面的值,不经过寄存器的复制直接赋值到main函数中。

所以我们可以得知:
1、临时变量具有常性

2、全局变量/静态变量/堆上变量,这些就可以用引用返回。

3、返回变量除了函数作用域就代表生命周期结束了(局部变量)

4、引用返回就不存在临时变量

 在这行代码中,ret一直是c的别名,ret就是该函数栈帧c的别名,无论c改成什么,ret就是什么,因为c就是ret,ret就是c。

传值、传引用效率比较:

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

#include <time.h>
struct A{ int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{A a;// 以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc1(a);size_t end1 = clock();// 以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc2(a);size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
c    out << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

 通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大
 

引用和指针的区别:
 

在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

int main()
{int a = 10;int& ra = a;cout<<"&a = "<<&a<<endl;cout<<"&ra = "<<&ra<<endl;return 0;
}

在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

int main()
{int a = 10;int& ra = a;ra = 20;int* pa = &a;*pa = 20;return 0;
}

 

引用和指针的不同点:

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

总结一下:
1、引用是别名,不开空间,指针是地址,需要开空间存储地址

2、引用必须初始化,指针可以初始化也可以不出初始化

3、引用不能改变指向,指针可以

4、引用相对更安全,没有空引用,但是由空指针和野指针。 

内联函数

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

如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的
调用。
查看方式:
1. 在release模式下,查看编译器生成的汇编代码中是否存在call Add
2. 在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不
会对代码进行优化,以下给出vs2013的设置方式)

1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会
用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运
行效率。
2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建
议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不
是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性

 

3.inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址
了,链接就会找不到

// F.h
#include <iostream>
using namespace std;
inline void f(int i);// F.cpp
#include "F.h"
void f(int i)
{cout << i << endl;
}// main.cpp
#include "F.h"
int main()
{f(10);return 0;
}链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl
f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用

 内联函数其实就是展开,将原本需要寻找函数地址的地方变成一系列函数定义。内联函数仅仅适合多次调用以及数据较少的函数代码。

auto关键字(C++11)

随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:

1. 类型难于拼写
2. 含义不明确导致容易出错
在编程时,常常需要把表达式的值赋值给变量,这就要求在声明变量的时候清楚地知道表达式的
类型。然而有时候要做到这点并非那么容易,因此C++11给auto赋予了新的含义。

在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但遗憾的
是一直没有人去使用它,大家可思考下为什么?
C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一
个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

int TestAuto()
{return 10;
}int main()
{int a = 10;auto b = a;auto c = 'a';auto d = TestAuto();cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化return 0;
}

使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto
的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编
译期会将auto替换为变量实际的类型。

auto的使用细则:

1.auto与指针和引用结合起来使用

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须
加&

int main()
{int x = 10;auto a = &x;auto* b = &x;auto& c = x;cout << typeid(a).name() << endl;cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;*a = 20;*b = 30;c = 40;return 0;
}

2. 在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译
器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量.

void TestAuto()
{auto a = 1, b = 2;auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

auto不能推导的场景:

1. auto不能作为函数的参数

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

2. auto不能直接用来声明数组

void TestAuto()
{int a[] = {1,2,3};auto b[] = {4,5,6};
}

3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法


4. auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等进行配合使用。
 

指针空值nullptr(C++11)

C++98中的指针空值

在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现
不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下
方式对其进行初始化 :

void TestPtr()
{int* p1 = NULL;int* p2 = 0;// ……
}

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

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何
种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int)
{cout<<"f(int)"<<endl;
}void f(int*)
{cout<<"f(int*)"<<endl;
}int main()
{f(0);f(NULL);f((int*)NULL);return 0;
}

程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的
初衷相悖。
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器
默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void
*)0。
 

1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入
的。
2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

 

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

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

相关文章

Leetcoder Day21| 回溯理论基础+组合

语言&#xff1a;Java/Go 回溯理论基础 回溯函数也就是递归函数&#xff1b; 所有回溯法的问题都可以抽象为树形结构&#xff1b; 回溯法解决的都是在集合中递归查找子集&#xff0c;集合的大小就构成了树的宽度&#xff0c;递归的深度&#xff0c;都构成的树的深度。 适用的题…

抖音数据抓取工具|短视频下载工具|视频内容提取软件

一、开发背景&#xff1a; 随着抖音平台的流行&#xff0c;越来越多的人希望能够下载抖音视频以进行个人收藏或分享。然而&#xff0c;目前在网上找到的抖音视频下载工具功能单一&#xff0c;操作繁琐&#xff0c;无法满足用户的需求。因此&#xff0c;我们决定开发一款功能强大…

ERROR: No matching distribution found for json

问题描述 安装 json库 的时候&#xff0c;一直报错&#xff1a; 解决方案&#xff1a; 大多数博文分享是&#xff1a;①网络问题&#xff0c;换国内镜像&#xff1b;②更新pip. 少有人提及在Python 3.10.1中&#xff0c;它叫 simplejson 了 pip install simplejson 参考&am…

【Golang】Golang使用embed加载、打包静态资源文件

【Golang】Golang使用embed加载、打包静态资源文件 大家好 我是寸铁&#x1f44a; 总结了一篇Golang使用embed加载静态资源文件的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 事情是这样的&#xff1a;前不久&#xff0c;有同学问我,golang怎么把静态资源文件打包成一…

在Ubuntu 16.04 LTS Xenial上安装最新的Linux manual page(man)中文手册manpages-zh(v1.6.4)

0. 写在前面 0.1 我的环境介绍 先说明&#xff0c;我的在虚拟机中装的Ubuntu 16.04 LTS Xenial。为什么要介绍这个呢&#xff1f;因为这个鸟系统太老了&#xff01;所以用apt安装的好多工具版本都好老&#xff01;由此用apt安装就会出现无穷无尽的问题。。。。。所以好多都要…

计算机设计大赛 深度学习图像修复算法 - opencv python 机器视觉

文章目录 0 前言2 什么是图像内容填充修复3 原理分析3.1 第一步&#xff1a;将图像理解为一个概率分布的样本3.2 补全图像 3.3 快速生成假图像3.4 生成对抗网络(Generative Adversarial Net, GAN) 的架构3.5 使用G(z)生成伪图像 4 在Tensorflow上构建DCGANs最后 0 前言 &#…

[算法沉淀记录] 排序算法 —— 冒泡排序

排序算法 —— 冒泡排序 基本概念 冒泡排序是一种简单的排序算法。它重复地遍历要排序的列表&#xff0c;一次比较两个元素&#xff0c;并交换它们的位置&#xff0c;如果它们不是按照升序排列的。这步遍历是重复进行的&#xff0c;直到没有再需要交换&#xff0c;也就是说该…

buuctf_N1BOOK_粗心的小李

题目&#xff1a; 看完题目&#xff0c;git下载文件&#xff1f;然后将.git文件传到线上环境&#xff1f;&#xff08;which 会造成git泄露的安全威胁&#xff09;<这个背景抱歉我不太了解哈&#xff0c;可能后续有补充> 这里主要记录做法过程&#xff1a; 工具&#xf…

phtread_cancel函数用于取消线程,但不是实时的

如上图所示&#xff0c;线程函数中没有取消点&#xff08;一般是一些系统调用----man 7 pthreads查看&#xff0c;自定义函数是无效的&#xff09;&#xff0c;则使用pthread_cancle函数不生效。 解决方法&#xff1a;可以添加pthread_testcancle(); 通过pthread_join回收的…

【C#】CNC 机器人的刀具路径生成软件PathCAM源码解析-Geometry

1. Loaders 1.1 DAE_Loader.cs 1.2 OBJ_Loader.cs 1.3 STL_Loader.cs 2. AnalyzedTriangleMesh.cs AnalyzedTriangleMesh类是一个用于分析和处理三角形网格&#xff0c;可以被用于将网格拆分为更小的部件或者识别特定特征的对象&#xff0c;如打印准备或几何分析&#xff0c;非…

力扣 187. 重复的DNA序列

1.题目 DNA序列 由一系列核苷酸组成&#xff0c;缩写为 A, C, G 和 T.。 例如&#xff0c;"ACGAATTCCG" 是一个 DNA序列 。 在研究 DNA 时&#xff0c;识别 DNA 中的重复序列非常有用。 给定一个表示 DNA序列 的字符串 s &#xff0c;返回所有在 DNA 分子中出现不止一…

Qt_纯虚函数的信号和槽

简介 在C中&#xff0c;纯虚函数是一个在基类中声明但没有实现的虚函数。纯虚函数的声明以 “ 0” 结尾。纯虚函数的目的是为了提供一个接口&#xff0c;但是不提供实现。派生类必须实现纯虚函数&#xff0c;否则它也会成为一个抽象类。纯虚函数可以在基类中定义&#xff0c;也…

一种新型的AlGaN/GaN HEMTs小信号建模与参数提取方法

来源&#xff1a;A new small-signal modeling and extraction methodin AlGaN/GaN HEMTs&#xff08;SOLID-STATE ELECTRONICS 07年&#xff09; 摘要 本文提出了一种新型的用于GaN HEMTs&#xff08;氮化镓高电子迁移率晶体管&#xff09;的小信号等效电路&#xff0c;包含2…

数学建模资料分享

1. 往年各赛题的优秀论文 可以用来参考一下论文是怎么写的。参考论文的结构&#xff0c;格式&#xff0c;思路等等。 链接&#xff1a;https://pan.baidu.com/s/1WG2t4-x9MjtaSgkq4ue5AQ?pwdnlzx 提取码&#xff1a;nlzx --来自百度网盘超级会员V4的分享 2.论文模板 链接&a…

【元宵佳节】砖一祝您节日快乐!

元宵节的由来 相传&#xff0c;汉文帝(前179-前157年)为庆祝周勃于正月十五勘平诸吕之乱&#xff0c;每逢此夜&#xff0c;必出言游玩&#xff0c;与民同乐&#xff0c;在古代&#xff0c;夜同宵&#xff0c;正月又称元月&#xff0c;汉文帝就将正月十五定为元宵节&#xff0c…

蓝桥杯《数字三角形》

题目描述 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径&#xff0c;把路径上面的数加起来可以得到一个和&#xff0c;你的任务就是找到最大的和。 路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。此外&…

关于Arrays类中asList(T... a)泛型参数辨析

前提 我们需要知道两点 &#xff08;1&#xff09;T指的是泛型类型&#xff0c;它只能是引用类型&#xff0c;何为引用类型&#xff1f;在java中除了基本数据类型&#xff08;如byte、short、int、long、float、double、boolean、char&#xff09;之外的所有类型都是引用类型…

SpringBootWeb请求响应

SpringBootWeb请求响应 这里写目录标题 SpringBootWeb请求响应前言1. 请求1.1 Postman1.1.1 介绍1.1.2 安装 1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致 1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象 1.4 数组集合参数1.4.1 数组1.4.2 集合 1.5 …

kafka生产者2

1.数据可靠 • 0&#xff1a;生产者发送过来的数据&#xff0c;不需要等数据落盘应答。 风险&#xff1a;leader挂了之后&#xff0c;follower还没有收到消息。。。。 • 1&#xff1a;生产者发送过来的数据&#xff0c;Leader收到数据后应答。 风险&#xff1a;leader应答…

小苯的IDE括号问题(CD) -----牛客小白月赛87(双链表)

C题&#xff1a;C-小苯的IDE括号问题&#xff08;easy&#xff09;_牛客小白月赛87 (nowcoder.com) D题&#xff1a; D-小苯的IDE括号问题&#xff08;hard&#xff09;_牛客小白月赛87 (nowcoder.com) C题代码&#xff1a; #include<bits/stdc.h>using namespace std…