【C++初阶】C++基础(下)——引用、内联函数、auto关键字、基于范围的for循环、指针空值nullptr

news2024/11/24 14:38:56

 

目录

1. 引用

1.1 引用概念

1.2 引用特性

1.3 常引用

1.4 使用场景

1.5 传值、传引用效率比较

1.6 引用和指针的区别

2. 内联函数

2.1 概念

2.2 特性

3.auto关键字(C++11)

3.1 类型别名思考

3.2 auto简介

3.3 auto的使用细则

3.4 auto不能推导的场景

4. 基于范围的for循环(C++11)

4.1 范围for的语法

4.2 范围for的使用条件

5. 指针空值nullptr(C++11)

5.1 C++98中的指针空值


❀❀❀没有坚持的努力,本质上并没有多大的意义。


1. 引用

1.1 引用概念

引用 不是新定义一个变量,而 是给已存在变量取了一个 别名 ,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

 类型& 引用变量名(对象名) = 引用实体(注意:引用类型必须和引用实体同种类型

b叫做a的引用,b也可以叫做a的别名(abcd四个,只要有一个发生变化,其余都发生变化)

应用1

void Swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

数据进行交换,可以不用传指针,可以用引用

应用2

#include <iostream>

typedef struct ListNode
{
	int val;
	struct ListNode* next;
}LTNode;

void LTPushBack_C(LTNode** pphead, int x)
{
	//C语言,单链表尾插需要传结构体的二级指针,因为需要改变首部地址
}

void LTPushBack_CPP(LTNode*& phead, int x)
{
	//C++中,用引用,仅仅需要传结构体地址
}

int main()
{
	LTNode* plist = NULL;
	//初始化
	LTPushBack_C(&plist, 1);
	LTPushBack_CPP(plist, 1);
	return 0;
}

也可以引用指针类型的 

注意:

typedef struct ListNode
{
	int val;
	struct ListNode* next;
}LTNode,*PLTNode;

void LTPushBack_CPP(LTNode*& phead, int x)
{
	//C++中,用引用,仅仅需要传结构体地址
}
//这两个等同
void LTPushBack_CPP(PLTNode& phead, int x)
{
	//C++中,用引用,仅仅需要传结构体地址
}

1.2 引用特性

代码展示:

#include <iostream>

int main()
{

	int a = 10;
	int& b = a;
	int& c = a;
	int& d = b;
	//一个变量可以多次引用
	int& e;//代码运行到这里会报错,因为引用在定义时必须初始化
	int m = 2;
	b = m;//b在前面已经引用了a,在这里并不是成为m的别名,而是把m的值赋值给b,然后此时abcd的值都是2
	return 0;
}
1. 引用在 定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体

1.3 常引用

const修饰的变量,只能读不能写(这里的权限,指的是读和写)

#include <iostream>

int main()
{
	int a = 0;
	int& b = a;//权限不变

	const int c = 2;
	int& d = c;//这里是错误的,权限不能被放大

	const int x = 3;
	const int& y = x;//这里是可以的,权限不变

	int m = 6;
	const int& n = m;//这里是可以的,权限缩小
	return 0;
}

取别名原则:对于引用类型,权限只能缩小,不能放大

临时变量具有常性

#include <iostream>

int main()
{
	int a = 10;
	int& b = a;

	const int& c = 20;//常量也可以取别名

	double d = 15.3;
	int f = d;//在这里,相当于f把自己的整数部分给一个临时变量,临时变量把值赋给f(临时变量具有常性)
	const int& e = d;//这里的e不是d的引用,而是临时变量的引用
	return 0;
}

 

1.4 使用场景

(1)做参数

void Swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

可以不用传指针

(2)做返回值

代码1展示:(传值返回)

#include <iostream>

int Count()
{
	int n = 0;
	n++;
	return n;
}//n出了这个函数就被销毁了,所以是赋值给临时变量的
int main()
{
	int ret = Count();

	return 0;
}

函数返回过程,把返回的值n给一个临时变量,临时变量的类型就是函数类型(上述代码的int),临时变量再把值赋给主函数的ret。(临时变量即有一个拷贝)

代码2展示:(传引用拷贝)

#include <iostream>
int& Count()
{
	static int n = 0;//static不能去掉,如果去掉,就会涉及出现越界问题(因为空间被系统回收)
	n++;
	return n;
}//返回int&,说明有一个临时引用是int&类型,临时引用是n的别名
int main()
{
	int& ret = Count();//ret是临时引用的别名,
	return 0;
}

没有拷贝,效率高

如果函数返回时,出了函数作用域,如果返回对象还在 ( 还没还给系统 ) ,则可以使用引用返回, 如果已经还给系统了,则必须使用传值返回。(否则会出现越界问题)

注意:

#include <iostream>
int Count()
{
	int n = 0;
	n++;
	return n;
}
int main()
{
	const int& ret = Count();//因为是临时变量的别名,临时变量具有常性
	return 0;
}

1.5 传值、传引用效率比较

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

1.6 引用和指针的区别

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

2. 内联函数

2.1 概念

inline 修饰 的函数叫做 内联函数 编译时 C++ 编译器会在 调用内联函数的地方展开 ,没有函数调用建立栈帧的开销,内联函数 提升程序运行的效率。
在函数前增加 inline 关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用

知识复习:写一个ADD的宏

 inline存在的意义:(1)解决宏函数晦涩难懂、容易写错(2)宏不支持调试

优点:(1)debug支持调试(2)不易写错,就是普通函数的写法(3)提升程序的效率

2.2 特性

1. inline 是一种 以空间换时间 的做法,省去调用函数额开销。所以 代码很长(大于10行) 或者有 循环 / 递归 的函数不适宜使用作为内联函数。
2. inline 对于编译器而言 只是一个建议 ,编译器会自动优化,如果定义为 inline 的函数体内有循环 / 递归等等,编译器优化时会忽略掉内联。
3. inline 不建议声明和定义分离 (头文件中,两个都写),分离会导致链接错误。因为 inline 被展开,就没有函数地址了,链接就会找不到。
知识点

宏的优缺点?
优点:
1. 增强代码的复用性。
2. 提高性能。
缺点:
1. 不方便调试宏。(因为预编译阶段进行了替换)
2. 导致代码可读性差,可维护性差,容易误用。
3. 没有类型安全的检查 。
C++ 有哪些技术替代宏
1. 常量定义 换用 const
2. 函数定义 换用内联函数

3.auto关键字(C++11)

3.1 类型别名思考

随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:
1. 类型难于拼写
2. 含义不明确导致容易出错

 auto可以自动定义类型,根据等号后面的变量

C++中,typeid(A).name();可以知道A的类型是什么

3.2 auto简介

在早期 C/C++ auto 的含义是:使用 auto 修饰的变量,是具有自动存储器的局部变量
C++11 中,标准委员会赋予了 auto 全新的含义即: auto 不再是一个存储类型指示符,而是作为一个新的类型 指示符来指示编译器, auto 声明的变量必须由编译器在编译时期推导而得
使用 auto 定义变量时 必须对其进行初始化 ,在编译阶段编译器需要根据初始化表达式来推导 auto 的实际类 。因此 auto 并非是一种 类型 的声明,而是一个类型声明时的 “占位符” ,编译器在编译期会将 auto 替换为 变量实际的类型

3.3 auto的使用细则

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

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

auto*定义的必须是指针类型

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

auto意义之一:类型很长时,懒得写,可以让他自动推导。 

3.4 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 表达式等进行配合使用。

4. 基于范围的for循环(C++11)

4.1 范围for的语法

C++11 中引入了基于范围的for 循环。 for 循环后的括号由冒号 分为两部分:第一部分是范围内用于迭代的变量, 第二部分则表示被迭代的范围
void TestFor()
{
	int array[] = { 1, 2, 3, 4, 5 };
	//加&的原因是e是array内容的拷贝,所以改变e不是改变array里面的内容
	for (auto& e : array)
	{
		e *= 2;
	}
	//范围for,依次自动取arrar中的数据,赋值给e,自动判断结束
	for (auto e : array)//这里写int也可以
	{
		cout << e << " ";
	}
}
与普通循环类似,可以用 continue 来结束本次循环,也可以用 break 来跳出整个循环

4.2 范围for的使用条件

1. for 循环迭代的范围必须是确定的
对于数组而言,就是数组中第一个元素和最后一个元素的范围 ;对于类而言,应该提供 begin end
方法, begin end 就是 for 循环迭代的范围。
注意:以下代码就有问题,因为 for 的范围不确定
void TestFor(int array[])
{
 for(auto& e : array)
 cout<< e <<endl;
}

这里的array是数组的首元素的地址,所以范围不定

2. 迭代的对象要实现 ++ == 的操作

5. 指针空值nullptr(C++11)

5.1 C++98中的指针空值


	//指针初始化
	int* p1 = NULL;
	int* p2 = 0;
	int* p3 = nullptr;//建议用这一种
C++98 中,字面常量 0 既可以是一个整形数字,也可以是无类型的指针 (void*) 常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0
注意:
1. 在使用 nullptr 表示指针空值时,不需要包含头文件,因为 nullptr C++11 作为新关键字引入的
2. C++11 中, sizeof(nullptr) sizeof((void*)0) 所占的字节数相同。
3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用 nullptr

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

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

相关文章

企业级IT应用运维监控层次架构设计

企业基本都有自己的IT系统&#xff0c;而每个IT系统都有自己的监控系统。 企业级的IT应用监控架构是一种综合性的解决方案&#xff0c;涉及到很多层级和相应的工具。随着企业IT系统的规模和复杂程度的不断增加&#xff0c;监控和管理系统也面临着越来越大的挑战。 大家有时在…

【算法心得】善用js可以把函数写在函数里的特性;善用spread表达式生成新数组

https://leetcode.cn/problems/combinations/ 善用js可以把函数写在函数里的特性 这样维护全局变量很烦 把子函数直接写在combine()内部&#xff0c;n和k可以直接用&#xff0c;也不用因为ans是全局的&#xff0c;每次来一个新的case要专门将ans清空了 善用spread表达式生成新…

2023年推荐的四款出色财务管理软件,助力您高效管理财务

在当今数字化时代&#xff0c;各类数字化工具逐渐普及&#xff0c;其中财务管理软件成为各个企业的标配工具。财务管理软件市场也逐渐百花齐放&#xff0c;那么2023年有什么好用的财务管理软件吗&#xff1f;本文就为大家推荐2023好用的四款财务管理软件&#xff01; 一. Zoho …

Vue 常用指令 v-model 双向数据绑定

之前的指令&#xff0c;无论使用哪一种&#xff0c;都是在代码当中定义的内容。在web开发当中经常要去获取用户的输入&#xff0c;v-model可以十分方便的将表单的值和实例当中的数据关联起来。 这样就可以十分便捷的获取和设置表单元素的值了。&#xff08;注意是表单元素&…

基于Spirngboot运动会管理系统

一&#xff1a;技术栈 SpringbootVueElement-UIMavenMysqlredis 二&#xff1a;角色 1.管理员&#xff08;创建运动会项目&#xff0c;视频&#xff0c;运动会开幕式等&#xff09; 2.裁判&#xff08;打分&#xff09; 3.运动员&#xff08;报名参赛&#xff09; 二&#…

每天一个电商API分享:获取淘宝商品描述详情 接口

电商商品描述在电商平台中扮演着重要的角色&#xff0c;对于商品销售和用户购物体验起到关键作用。以下是电商商品描述的重要性&#xff1a; 吸引用户&#xff1a;商品描述是吸引用户的第一步。通过生动、详细、精准的商品描述&#xff0c;可以吸引用户的注意力&#xff0c;引起…

Posix API原理返回值说明

文章目录 1、概述2、connect函数3、listen函数4、accept返回值处理5、recv返回值处理5.1、LT\ET模式读取数据 6、send返回值处理 1、概述 主要介绍网络编程中&#xff0c;使用到的一些系统调用解释&#xff0c;以及返回值的说明 2、connect函数 connect函数功能为&#xff0c;客…

牛客网Verilog刷题——VL51

牛客网Verilog刷题——VL51 题目答案 题目 请编写一个十六进制计数器模块&#xff0c;计数器输出信号递增每次到达0&#xff0c;给出指示信号zero&#xff0c;当置位信号set 有效时&#xff0c;将当前输出置为输入的数值set_num。模块的接口信号图如下&#xff1a; 模块的时序图…

CS人的痛

FDU原题详情请见&#xff1a;机试合集&#xff0c;选取一些学习的&#xff0c;求上岸 2022.3---CP1514 概率最大路径 题目描述&#xff1a; 2021.3---CP494 目标和 题目描述&#xff1a;

【雕爷学编程】Arduino动手做(177)---ESP-32 掌控板4

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

M5ATOMS3基础04给ROS2发一个问候(micro-ROS)

参考以往部分历程&#xff1a; 1. esp32与ros2的欢乐启程 2021 2. micro-ROS之esp32与ros2资料&#xff08;freertos&#xff09; 2021 3. esp32发布机器人电池电压到ros2&#xff08;micro-rosCoCube&#xff09; 2022 4. CoCube和Micro-ROS简单案例演示 2022 不需要僵化的…

面试总结(三)

1.进程和线程的区别 根本区别&#xff1a;进程是操作系统分配资源的最小单位&#xff1b;线程是CPU调度的最小单位所属关系&#xff1a;一个进程包含了多个线程&#xff0c;至少拥有一个主线程&#xff1b;线程所属于进程开销不同&#xff1a;进程的创建&#xff0c;销毁&…

交流电气装置防雷接地电阻测量的方案

一、目的 为了保证交流电气装置的安全运行和防止雷电对其造成损坏&#xff0c;需要定期检测其接地装置的接地电阻&#xff0c;评估其接地效果和防雷性能。 二、原理 地凯科技认为&#xff1a;接地电阻是指接地装置与大地之间的电阻&#xff0c;它反映了接地装置与大地的接触…

【104协议】【光伏电站】电站系统中的104协议学习

文章目录 104协议学习I帧S帧U帧ASDU总结&#xff1a;关于各类帧的通俗描述建立流程详细分析 104协议学习 起始一个apdu的总长度不会超过255个字节&#xff1b; 在协议中的第二个字节会记录本apdu的长度&#xff0c;但是这个记录的长度数是除开前面两个字节之外的长读数&#xf…

【C++】开源:Linux端V4L2视频设备库

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Linux端V4L2视频设备库。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下…

笨办法学python3进阶篇pdf,笨办法学python3pdf完整版

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;笨办法学python 3电子书下载&#xff0c;笨办法学python3pdf完整版&#xff0c;今天让我们一起来看看吧&#xff01; 1、笨方法学python习题43 按照你说的 Map是一个类&#xff0c;scene_map是一老胡镇个类实例 scene_…

Scratch 详解 流畅光线追踪(盲区)引擎:角度 + 一次函数 + 区域判断

【提示1】本文将全程使用原版积木实现这一功能&#xff0c;请不要在评论区发送扩展中有相应积木。若喜欢使用扩展&#xff0c;可以自行将本文介绍的方法用扩展积木替代。 【提示2】本文中代码里出现的所有最后带*号的变量&#xff0c;均为私有变量&#xff01; 正文 近日&…

C数据结构——无向图(邻接矩阵方式) 创建与基本使用

源码注释 // // Created by Lenovo on 2022-05-13-上午 9:06. // 作者&#xff1a;小象 // 版本&#xff1a;1.0 //#include <stdio.h> #include <malloc.h>#define MAXSIZE 1000 // BFS队列可能达到的最大长度 #define MAX_AMVNUMS 100 // 最大顶点数typedef enu…

用SpringBoot实现post和get请求(多图)

用SpringBoot实现post和get请求&#xff08;多图&#xff09; 用SpringBoot实现post和get请求创建SpringBoot工程创建controller验证FAQ创建项目后依赖报错Project org.springframework.boot:spring-boot-starter-parent:3.1.2.RELEASE not found more 用SpringBoot实现post和g…

AQS构建锁和同步器的框架

1.概述 AQS全称AbstractQueuedSynchronizer&#xff0c;此类在java.util.concurrent.locks包下面&#xff0c;是一个构建锁和同步器的框架&#xff0c;比如ReentrantLock就是基于AQS来实现的。 2.AQS实现原理 AQS内部有一个由volatile修饰(保证其可见性)的变量state&#xf…