【C++初阶】C++入门——内联函数、auto、范围for、nullptr

news2024/11/26 15:01:40

在这里插入图片描述

文章目录

  • 一、内联函数
    • 1.1 定义
    • 1.2 特性
  • 二、auto关键字
    • 2.1 简介
    • 2.2 auto使用细则
    • 2.3 不能使用auto的场景
  • 三、基于范围的for循环
    • 3.1 范围for的使用条件
  • 四、指针空值nullptr

一、内联函数

 普通的函数在调用的时候会开辟函数栈帧,会产生一定量的消耗,在C语言中可以用宏函数来解决这个问题,但是宏存在以下缺陷:复杂、容易出错、可读性差、不能调试。为此,C++中引入了内联函数这种方法。

1.1 定义

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

int Add(int x, int y)//这里的Add是一个普通函数
{
	return x + y ;
}

int main()
{
	int ret = 0;
 	ret = Add(3, 5);
	cout << ret << endl;
	return 0;
}

在这里插入图片描述
🪆内联函数:

inline int Add(int x, int y)
{
	return x + y ;
}

int main()
{
	int ret = 0;
 	ret = Add(3, 5);
	cout << ret << endl;
	return 0;
}


注意:在默认的Debug模式下,内联函数是不会展开的,需要进行设置,设置过程如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 特性

  • inline是一种以时间换空间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用缺陷:可能会使目标文件变大,优点:少了调用开销,提高程序运行效率。
  • inline对编译器而言只是建议,不同的编译器关于inline的实现机制可能不同,一般建议:将函数规模小的(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。
  • inline建议函数声明和定义不能分离,因为内联函数在预处理阶段就直接展开,因此内联函数不会进符号表,因此如果声明和定义分离,头文件只有声明,在预处理阶段,头文件展开,只知道该函数是一个内联函数,没有对应函数的定义,因此就无法完成替换,那就只能等通过call在链接阶段去找该函数,但是它是内联函数,没有进符号表,所以链接阶段就会报错。

🪆为什么是函数规模小?
 假设一个函数经过编译,得到五十条汇编指令。普通情况下,调用此函数只需要一条call指令,调用10000此也就10000条call指令,但是如果把这个函数设置成内联函数,指令的数量就会大大增加,因为内联函数完成的是替换,把所有调用它的地方,都用函数体去替换,这也就意味着,原来1条call指令就能完成的任务,现在替换后就变成了50条指令,假如还是调用了10000次该函数,那就从10000条call指令,变成了500000条指令,其实这就是代码膨胀

inline int Add(int x, int y)
{
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	cout << "xxxxxxxxxxxx" << endl;
	return x + y ;
}

int main()
{
	int ret = 0;
 	ret = Add(3, 5);
	cout << ret << endl;
	return 0;
}

在这里插入图片描述
 对于上面函数体比较长的函数,即使我们人为规定了它是内联,但最终还是通过call指令去调用函数。

🪆为什么是被频繁调用?
 因为普通函数在调用的时候会创建函数栈帧,若频繁调用就会频繁的创建栈帧,增加消耗。宏和内联,就是为了解决开销问题。如果调用的次数不多,开辟一点栈帧是无所谓的。

二、auto关键字

2.1 简介

 C++11中规定:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。简单来说,auto会根据表达式自动推导类型。

int main()
{
	int a = 0;
	auto b = a;//自动推导出b的类型是int
	auto c = 1.11 + 1;//自动推导出c的类型是double
	cout << typeid(b).name() << endl;//typeid可用来查看变量类型
	cout << typeid(c).name() << endl;
	return 0;
}

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

int main()
{
	auto a;//错误,必须要初始化
	return 0;
}

在这里插入图片描述

2.2 auto使用细则

🪆auto与指针和引用结合起来使用
 用auto声明指针类型时,用auto和aauto*没有任何区别,但是auto声明引用类型时,必须要加&,如下,如果c不加&的话,就是x的一份拷贝。

int main()
{
	int x = 10;
	auto a = &x;//根据右边推出,a是一个指针类型
	auto* b = &x;//右边必须是一个地址,因为前面加了*
	auto& c = x;//引用必须要加&
}

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

int main()
{
	auto a = 10, b = 30;
	auto c = 60, d = 1.1;//该行编译失败,c和d的初始化类型不同
}

在这里插入图片描述

2.3 不能使用auto的场景

  • auto不能作为函数的参数
//错误,编译器无法对x的实际类型进行推导
void Text(auto x)
{}
  • ·auto不能直接用来声明数组
void Text()
{
	//auto arr[] = { 1, 2, 3 };//错误写法,请勿模仿
	int arr[] = {1, 2, 3}//这才是正确写法
}

小Tips:auto在实际中常被用在:基于范围的for循环中、还有lambda表达式中、其次就是一些非常非常长的类型,也会用auto进行替换。

三、基于范围的for循环

🪆C++98中遍历一个数组:

void TestFor()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)//通过下标访问
     	array[i] *= 2;
	for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p)//通过指针访问
     	cout << *p << endl;
}

🪆C++98中遍历一个数组:
 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还容易犯错误。因此C++11中引入了基于范围for循环。for循环后的括号由冒号“ : ”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围

void TestFor()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for(auto& e : array)//加引用可以对后面的值修改
     	e *= 2;
	for(auto e : array)
     	cout << e << " ";
	return 0;
}

3.1 范围for的使用条件

  • for循环迭代的范围必须是确定的
  • 迭代的对象要实现++和==的操作

 对数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end方法,begin和end就是for循环的迭代范围。范围for本质上是迭代器,支持迭代器就支持范围for

void Text(int arr[])//arr本质上只是一个地址,没有范围
{
	for (auto a : arr)//错误
	{
		cout << a << endl;
	}
}

四、指针空值nullptr

 良好的编程习惯要求我们,在声明一个变量时最好给该变量一个合适的初始值,否则可能出现不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们一般会把它置空。
🪆回顾NULL:

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

在这里插入图片描述
 上述代码的本意是:希望通过f(NULL);去调用void f(int*),但是通过执行结果可以看出,f(NULL);调用的是void f(int)。这是因为NULL被定义成了0,且C++98中规定,字面常量0,既可以是一个整型数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成一个整型常量,如果要将其按照指针的方式来使用,必须对其进行强制类型转换(void*)0
在这里插入图片描述
🪆认识nullptr:
nullptr用来表示指针空值,因为nullptr是C++11作为新关键字引入的,所以在使用的时候不需要包头文件。C++11中,sizeof(nullptr)sizeof((void*)0)所占字节数相同。

int main()
{
	cout << sizeof(nullptr) << endl;
	cout << sizeof((void*)0) << endl;
	return 0;
}

在这里插入图片描述


 今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,您的支持就是春人前进的动力!
在这里插入图片描述

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

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

相关文章

《算法竞赛·快冲300题》每日一题:“推箱子”

《算法竞赛快冲300题》将于2024年出版&#xff0c;是《算法竞赛》的辅助练习册。 所有题目放在自建的OJ New Online Judge。 用C/C、Java、Python三种语言给出代码&#xff0c;以中低档题为主&#xff0c;适合入门、进阶。 文章目录 题目描述题解C代码Java代码Python代码 “ 推…

1 考试宝自建题库使用说明

注意&#xff1a; 标准格式&#xff1a;括号里不写对象&#xff0c;然后答案行数另取一行&#xff0c;放在选项后一行也是可以的&#xff0c;选项可以横排或者竖排。横排的话选项要用空格隔开&#xff0c;选项的ABCD要加"."&#xff0c;如A. B. C. D. 1. 法治中国…

多个电源模块带电感,给一个负载用的直流压降仿真-CORE电源

多个电源模块带电感,给一个负载用的直流压降仿真-CORE电源 下面介绍如何对多个电源模块带电感,给一个负载用的直流压降仿真,常见于CPU的CORE电源。以下图为例 具体操作步骤如下 设置VRAM(因为是多个电源输出,所以每个电源都要设置成VRAM)

【C语言】轻松模拟实现qsort函数

君兮_的个人主页 勤时当勉励 岁月不待人 C/C 游戏开发 Hello,米娜桑们&#xff0c;这里是君兮_&#xff0c;我们今天接着上回更新的内容&#xff0c;讲讲我们如何模拟实现自己的qsort函数&#xff0c; 废话不多说&#xff0c;我们开始今天的内容。 模拟实现qsort函数 qsort函…

文心一言 VS 讯飞星火 VS chatgpt (59)-- 算法导论6.4 3题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;59&#xff09;-- 算法导论6.4 3题 三、对于一个按升序排列的包含 n 个元素的有序数组 A 来说&#xff0c;HEAPSORT 的时间复杂度是多少?如果 A 是降序呢? 文心一言&#xff1a; 对于一个按升序排列的包含 n 个元素的有序数组…

ModaHub魔搭社区:AI原生云向量数据库Weaviate 对比 Milvus

通过以下一系列能力比较 Weaviate 对比 Milvus。我们希望您选择适合您的最佳开源数据库,即使它不是我们。 Weaviate 与 Milvus 可扩展性对比 Weaviate Milvus 计算存储分离 ❌ ✔️ 支持 10 亿级向量数据 ❌ ✔️ 云原生 ✔️ ✔️ 多副本 ✔️ ✔️ 查询插入分离

第一次用用Opencv进行图像处理

2023.7.06更新 codeblocks安装opencv 直接放参考链接&#xff0c;完成安装该步骤来&#xff0c;简单高效&#xff01; 安装教程链接 有一个问题就是第一次安装完成后运行时会报确实某些ddl的错误&#xff0c;关机重启就好啦&#xff01; 尝试运行 ddl的错误解决后可以用以…

用Python采用Modbus-Tcp的方式读取PLC模块数据

使用计算器得到需要的寄存器地址 这里PLC地址是83,对应的程序16进制读取地址是53 实际上由于PLC地址从1开始&#xff0c;所以这里实际地址应该是52&#xff0c;因为计算机从0开始 使用网络调试助手生成报文 使用Python中的内置函数int()。以下是将人员卡号’b’3b44’转换为十…

mac批量提取文件夹的名称,怎么操作?

mac批量提取文件夹的名称&#xff0c;怎么操作&#xff1f;很多小伙伴想知道在mac电脑上可以一键快速批量的将大量文件夹的名提取出来&#xff0c;而不是采用一个一个名称提取的方法&#xff0c;这是一个有利于提高工作效率的办法&#xff0c;这一项技能在网上几乎找不到解决办…

智能感测型静电消除器的原理

感测型静电消除器是一种能够监测和消除静电的装置。静电是由于物体表面积聚了不平衡的电荷而产生的现象&#xff0c;常常会引发电击、火花、物体吸附等问题。 感测型静电消除器通常包含以下几个主要部分&#xff1a; 1. 传感器&#xff1a;用于检测静电电荷的存在和强度。传感…

V4l2-ctl

1 v4l-utils v4l-utils是一种用于处理媒体设备的软件包&#xff0c;它主要包含两个常用工具1&#xff1a; media-ctl&#xff1a;用于配置拓扑结构中各节点的format、大小、链接&#xff1b;操作/dev/medio0节点&#xff1b;获取Camera支持数据格式等。v4l2-ctl&#xff1a;用…

Java面试为啥会越来越难?

最近感慨面试难的人越来越多了&#xff0c;一方面是市场环境&#xff0c;更重要的一方面是企业对Java的人才要求越来越高了。 基本上这样感慨的分为两类人&#xff0c;第一&#xff0c;虽然挂着3、5年经验&#xff0c;但肚子里货少&#xff0c;也没啥拿得出手的项目&#xff0c…

追妹神器,恋爱神器,哄老婆开心,智能机器人每天给你心爱的TA发送早晚安问候

柠檬恋爱助理配置文档 柠檬恋爱助理插件是利用微信测试公众号&#xff0c;实现每天给你的TA发送早晚安等模板消息的一款全自动化插件&#xff0c;恋爱神器、追妹神器。真正做到只需简单配置&#xff0c;就可以实现哄你的TA开心快乐每一天。 项目地址&#xff1a;点击查看 体…

【C语言】-- 一篇带你了解指针数组与数组指针

目录 一、什么是指针数组和数组指针 1. 指针数组&#xff1a;顾名思义&#xff0c;存放指针的数组。 补充&#xff08;1&#xff09;&#xff1a;指针数组还可以和字符串数组相结合使用 补充&#xff08;2&#xff09;&#xff1a;二维数组与指针数组的区别 2. 数组指针&am…

UriComponentsBuilder使用发现参数被编码了

前言 开发中&#xff0c;小编在项目中&#xff0c;使用RestTemplate做GET请求&#xff0c;为了优雅的封装参数&#xff0c;使用了UriComponentsBuilder来进行参数封装。直接123将代码写完&#xff0c;远程调用有数据&#xff0c;远程底层solr库&#xff0c;所以拿到数据了&…

Linux的基本使用和web程序部署

注意&#xff1a;本文章不适合C学习者&#xff08;知识点远远不够&#xff09;&#xff0c;只适合Java学习者&#xff0c;学习简单的Linux命令 1.Linux的背景知识 1.1Linux是什么 Linux是一个操作系统&#xff0c;和Windows是“并列”的关系。经过多年的发展&#xff0c;Lin…

控制台警告:Added non-passive event listener to a scroll-blocking <some> event

页面中的echarts图表缩放后在控制台就会出现以下提醒&#xff0c;虽然只是报黄提醒&#xff0c;但本人强迫症严重,见不得控制台有任何异常...... [Violation] Added non-passive event listener to a scroll-blocking <some> event. Consider marking event handler as …

python+pytest接口自动化之测试函数、测试类/测试方法的封装

目录 前言 测试用例封装的一般规则 测试函数的封装 测试类/方法的封装 示例代码 总结 前言 在pythonpytest 接口自动化系列中&#xff0c;我们之前的文章基本都没有将代码进行封装&#xff0c;但实际编写自动化测试脚本中&#xff0c;我们都需要将测试代码进行封装&#…

并不简单的代理,Dubbo是如何做服务引用的

系列文章目录 【收藏向】从用法到源码&#xff0c;一篇文章让你精通Dubbo的SPI机制 面试Dubbo &#xff0c;却问我和Springcloud有什么区别&#xff1f; 超简单&#xff0c;手把手教你搭建Dubbo工程&#xff08;内附源码&#xff09; Dubbo最核心功能——服务暴露的配置、使用…

2023/07/14 UML图/流程图/泳道图是什么

UML图 UML图中的几种图简介&#xff08;时序图&#xff0c;协作图&#xff0c;状态图&#xff0c;活动图&#xff0c;对象图&#xff09; 泳道图 适合做这种效果&#xff0c;体现角色关系 流程图 定义 绘制要素 开始/结束&#xff1a;用一个椭圆标识&#xff0c;代表流畅的开…