【C++】踏上C++学习之旅(五):auto、范围for以及nullptr的精彩时刻(C++11)

文章目录

  • 前言
  • 1. auto关键字(C++11)
    • 1.1 为什么要有auto关键字
    • 1.2 auto关键字的使用方式
    • 1.3 auto的使用细则
    • 1.4 auto不能推导的场景
  • 2. 基于范围的for循环(C++11)
    • 2.1 范围for的语法
    • 2.2 范围for的使用条件
  • 3. 指针空值nullptr(C++11)
    • 3.1 为什么会有nullptr这个关键字?

图片

前言

本文我了解一下C++11新特性的auto、范围for以及nullptr给我们的编程带来了什么样的好处,以及我们在特定的场景该如何使用它们。

温馨提示:本文所讲到的C++11(2011年)和C++98(1998年)均为C++编译器的版本。

OK,让我们一起探索这些auto、范围for以及nullptr背后的秘密。

哈哈哈


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

这里需要说明的一点是,在C++98就已经有auto这个关键字了。不过在C++98的做法中,它将auto关键字视作一个存储类型的指示符。换句话说,只要是在C++98中使用auto关键字定义的变量就是一个具有自动存储器功能的局部变量 – 待补充

1.1 为什么要有auto关键字

这就要往类型别名的方向去思考这个问题。

想一个现象,随着我们越学到后面,代码就会变得愈加复杂,伴随的是声明类型的长度也会增加,这个就会导致两个问题:

  1. 类型难以拼写;
  2. 类型含义不明确导致出错。

这么说可能有点干巴,下面我来展示一段代码(这个是大家以后学习C++要用到的):

#include<iostream>
#include<string>
#include<map>
#include<vector>
using namespace std;

int main()
{
	std::map<std::string, std::string> m{ {"apple","苹果"},{"orange","橙子"},{"pear","梨"} };

	std::map<std::string, std::string>::iterator it = m.begin();

	while (it != m.end())
	{
		//...
	}
	return 0;
}

上面的std::map<std::string, std::string>std::map<std::string, std::string>::iterator,这两个类型够长吧,即使你能记得住,如果有很多地方都要定义的话,我估计你的键盘可能会敲冒烟。

那有的人就会这么想,那我可以用typedef来给这些长的类型起一个别名,比如下面这样:

#include<iostream>
#include<string>
#include<map>
#include<vector>
using namespace std;
typedef std::map<std::string, std::string>  Map;

int main()
{
	Map m{ {"apple","苹果"},{"orange","橙子"},{"pear","梨"} };

	Map::iterator it = m.begin();

	while (it != m.end())
	{
		//...
	}
	return 0;
}

这个方法确实是可以的,但是你能确保在庞大的代码量面前,你能十分的明确Map这个类型所代表的具体含义吗?本人觉得这是一件很难的事,另外用typedef关键字,还有个重要的细节:

#include<iostream>
using namespace std;

typedef int* int_ptr;
int main()
{
	int num1 = 66,num2 = 88;
	//写法1:
	int_ptr a = &num1 , b = &num2;
	//写法2:
	int_ptr a = &num1 , *b = &num2;
	//以上两种写法那个是正确的?
}

答案:写法一是正确的。

#include<iostream>
using namespace std;

int main()
{
	int num1 = 66,num2 = 88;
	//写法1:
	int* a = &num1 , b = &num2;
	//写法2:
	int* a = &num1 , *b = &num2;
	//以上两种写法那个是正确的?
}

答案:写法二是正确的。

如果你上面两道题目做对了一道的话,那我想auto关键字就很适合你使用了!

1.2 auto关键字的使用方式

🍉auto 变量名 = 值;
🍇编译器在编译的过程看到auto就会根据赋值符号右边的表达式推导出出变量名的类型!

#include<iostream>
using namespace std;

int main()
{
	auto a = 's';
	auto b = 66;
	auto c = 520.13f;
	auto d = 0.1314;

	//auto也可以推导出表达式的值的数据类型
	auto tmp = b + d;

	//我们可以用typdeid(变量名).name()
	cout << typeid(a).name() << endl;
	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;
	cout << typeid(tmp).name() << endl;

	return 0;
}

测试结果

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

1.3 auto的使用细则

  1. auto与指针和引用结合起来使用
    用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&。
	//auto*和auto用来代表指针类型都是一样的,但是如果我们要用引用的话,就必须在auto后面加上&。
	int a = 10;
	int b = 66;
	int c = 88;

	auto* pa = &a;
	auto pb = &b;
	auto& ic = c;

	cout << typeid(pa).name() << endl;
	cout << typeid(pb).name() << endl;
	cout << typeid(ic).name() << endl;

	return 0;

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

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

1.4 auto不能推导的场景

  1. auto不能作为函数的形参
// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}
  1. auto不能直接声明数组
void TestAuto()
{
    int a[] = {1,2,3};
    auto b[] = {456}; //会报错
}

好了,到这里auto关键字的用法也了解的差不多了。那么接下来我们再来看看C++的一个"语法糖"——“范围for”!
hahah


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

2.1 范围for的语法

我们在C++98中如果要遍历一个数组,是这样做的:

void TestFor()
{
	int arr[] = {1,2,3,4,5,6,7,8,9,0};
	for(int i = 0 ; i < sizeof(arr) / sizeof(int); ++i)
	{
		cout<< arr[i] << ' ';
	}
	cout << endl;
	
	for(int* p = arr; p < arr + sizeof(arr)/sizeof(int); p++)
	{
		cout << *p << ' ';
	}
	cout << endl;
	
}

==对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。==因此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;
}

注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。

2.2 范围for的使用条件

  1. for循环迭代的范围必须是确定的
    对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

注意:以下代码就有问题,因为for的范围不确定

void TestFor(int array[])
{
    for(auto& e : array)
        cout<< e <<endl;
}
  1. 迭代的对象要实现++和==的操作。(关于迭代器这个问题,以后会讲,现在提一下,没办法讲清楚,现在大家了解一下就可以了)

范围for比较简单,只要求会用就可以了。那接下来再来讲讲另一个关键字"nullptr"!


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

3.1 为什么会有nullptr这个关键字?

有的读者可能会诧异,不是说C++兼容C语言吗?那我们就直接用C语言的NULL作为来表示指针空值就行了啊,为什么C++还要单独再弄一个nullptr关键字出来呢?

我们可以查看C++下的NULL:
在main函数中敲一个NULL,之后点击鼠标右键,然后点击"转到定义"。
步骤一
NULL定义的地方:
大
可以看到的是NULL在cpp文件中是字面常量0

如果我们要是在C++中用NULL,可能会遇到一些麻烦,比如下面的这段代码:

void f(int)
{
	cout << "void f(int)" << endl;
}

void f(int*)
{
	cout << "void f(int*)" << endl;
}

int main()
{
	f(0);
	f(NULL);
	f((int*)NULL);
}

图

程序本意是想通过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。

好了,到这里,你感受到了auto、范围for和nullptr的魅力了吗?

如果觉得本文写的不错的话,麻烦给偶点个赞吧!!!

hahaha

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring】Spring的简单创建和使用

前言 Spring Bean 可以通过两种主要方式定义&#xff1a;基于 XML 配置文件和基于注解。今天我们讲解基于 XML 配置文件‌来定义 Bean &#xff0c;在 XML 配置文件中&#xff0c;使用 <bean> 元素定义 Bean&#xff0c;描述 Bean 的创建、配置和依赖关系&#xff0c;并存…

二次封装 el-pagination 组件存在的问题

在使用 Element Plus 组件时&#xff0c;有时会遇到组件不完全符合需求的情况&#xff0c;这时可能需要对其进行二次封装。在封装 Pagination 组件时&#xff0c;我们会发现一些属性和函数无法正常使用&#xff0c;下面将详细探讨这些问题&#xff0c;并提供一下思路和想法。 …

想唱就唱 2.15.63| 电视免VIP唱K软件,支持手机点歌

想唱就唱是一款实用性强的K歌软件&#xff0c;支持歌曲搜索、歌手搜索及排行榜。软件支持歌曲下载、点歌、插队&#xff0c;还支持手机扫码点歌&#xff0c;功能与KTV软件一致&#xff0c;让用户在家也能享受KTV体验。首次加载较慢&#xff0c;因采用先下载后播放方式。会员版已…

图文深入介绍Oracle DB link(一)

1. 引言&#xff1a; 本文图文深入介绍Oracle DB link&#xff0c;先介绍基本概念。 2.DB link的定义 数据库链接&#xff08;Database Link&#xff0c;简称 DB Link&#xff09;是 Oracle 数据库中的一个重要功能。它是一种在一个 Oracle 数据库实例中访问另一个 Oracle 数…

江协科技STM32学习- P34 I2C通信外设

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

vxe-table 表格中实现多行文本的编辑

Vxe UI vue vxe-table 表格中实现多行文本的编辑 vxe-table v4.8 要在表格中使用多行文本编辑&#xff0c;可以通过设置行高方式&#xff0c;再设置 cell-config.verticalAlign: ‘top’ 单元格垂直对齐方式&#xff0c;实现顶部对齐&#xff0c;因为默认是居中对齐。 代码 …

Linux开发工具——make/Makefile

目录 一、什么是makefile&#xff1f; 二、为什么要有makefile&#xff1f; 三、makefile的使用 1.依赖关系与依赖方法 2.伪目标 3.定义变量 4.特殊符号 四、makefile的执行逻辑 一、什么是makefile&#xff1f; Makefile是一种自动化构建工具&#xff0c;make是一条指…

`掌握Python-PPTX,让PPt制作变得轻而易举!`

文章目录 掌握Python-PPTX&#xff0c;让PPT制作变得轻而易举&#xff01;背景介绍python-pptx 是什么&#xff1f;如何安装 python-pptx&#xff1f;简单库函数使用方法应用场景常见Bug及解决方案总结 掌握Python-PPTX&#xff0c;让PPT制作变得轻而易举&#xff01; 背景介绍…

uniapp vue3 使用echarts-gl 绘画3d图表

我自己翻遍了网上&#xff0c;以及插件市场&#xff0c;其实并没有uniapp 上使用echarts-gl的样例&#xff0c;大多数都是使用插件市场的echarts的插件 开始自己尝试直接用echartsgl 没有成功&#xff0c;后来尝试使用threejs 但是也遇到一些问题&#xff0c;最后我看官网的时…

windows运行ffmpeg的脚本报错:av_ts2str、av_ts2timestr、av_err2str => E0029 C4576

问题描述 我目前的环境是&#xff1a; 编辑器&#xff1a; Microsoft Visual Studio Community 2022 (64 位) 运行的脚本是ffmpeg自带的remux样例&#xff0c;只不过我想用c语言执行这个样例。在执行的过程中报错如下图&#xff1a; C4576 后跟初始值设定项列表的带圆括…

Moore Perf System 1.1版本

Moore Perf System&#xff08;一款性能分析工具&#xff09; 提供可视化界面&#xff0c;在时间轴上按时间顺序显示 CPU 和 GPU 的事件、吞吐和性能指标&#xff0c;帮助开发人员方便、快速、准确的定位到系统级别的性能瓶颈&#xff0c;进而进行针对性分析和优化&#xff0c;…

『VUE』19. scope避免组件之间样式互相覆盖(详细图文注释)

目录 使用多个组件带有样式分析如何避免css覆盖总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 使用多个组件带有样式 ComPonent1.vue <template><h3>ComPonent1.vue</h3> </template><script&g…

数据结构 C/C++(实验二:栈)

&#xff08;大家好&#xff0c;今天分享的是数据结构的相关知识&#xff0c;大家可以在评论区进行互动答疑哦~加油&#xff01;&#x1f495;&#xff09; 目录 提要&#xff1a;实验题目 一、实验目的 二、实验内容及要求 三、算法思想 实验1 实验2 四、源程序及注释…

软考背诵笔记

计算机硬件组成 运算器&#xff0c;控制器&#xff0c;存储器&#xff0c;输入设备&#xff0c;输出设备 中央处理单元&#xff08;CPU&#xff09; 控制器组成 指令寄存器&#xff08;IR&#xff09;:暂存cpu执行指令 程序计数器&#xff08;PC&#xff09;:存放下一条执…

面试问答-1

目录 1、线程和进程的概念&#xff0c;区别、以及什么时候用线程什么时候用进程 1.1 概念 1.2 区别 1.3 选择 2、TCP/IP分几层&#xff0c;每层的核心任务是什么 1.tcp/ip模型 tcp&#xff1a; udp&#xff1a; tcp、udp的区别 tcp/udp的连接过程&#xff1a; 3、htt…

矩阵特殊打印方式

小伙伴们大家好&#xff0c;好几天没更新了&#xff0c;主要有个比赛。从今天起继续给大家更新&#xff0c;今天给大家带来一种新的题型&#xff1a;矩阵特殊打印方式。 螺旋打印矩阵 解题思路 首先给大家看一下什么是螺旋方式打印&#xff1a; 就像这样一直转圈圈。 我想大多…

Docker篇(Docker安装)

目录 一、Centos7.x 1. yum 包更新到最新 2. 安装需要的软件包 3. 设置 yum 源为阿里云 4. 安装docker 5. 安装后查看docker版本 6. 设置ustc镜像源 二、CentOS安装Docker 前言 1. 卸载&#xff08;可选&#xff09; 2. 安装docker 3. 启动docker 4. 配置镜像加速 …

计算机网络——路由器构成

算路由表是分布式去算——你算你的&#xff0c;我算我的 输出队列非先来先传 调度发生在哪里 缓存队列一般是应对——来数据方向的速度过快问题

C# 实现读取Excel文件并设置单元格计算公式再保存

背景&#xff1a;需求需要读取数据导出成Excel文件&#xff0c;并且其中有一列需要赋值为公式&#xff0c;用于用户自己修改数据自动计算 导出Excel&#xff0c;我用到开源包MiniExcel Gitee地址MiniExcel源码介绍&#xff0c;功能说明 Nuget安装 搜索MiniExcel 导出代码如下&a…

基于matlab的SVPWM逆变器死区补偿算法仿真研究

背景介绍&#xff1a; 三相脉宽调制(pulse width modulation&#xff0c;PWM)电压源逆变器(voltage source inverter&#xff0c;VSI)的死区效应可导致电机相电压和相电流畸变、零电流钳位效应以及转矩和转速脉动&#xff0c;系统性能降低。为提高系统运行性能&#xff0c;对V…