• 【C++初阶(四)aoto关键字与基于范围的for循环】


    本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。

    💓博主csdn个人主页小小unicorn
    ⏩专栏分类:C++
    🚚代码仓库:小小unicorn的代码仓库🚚
    🌹🌹🌹关注我带你学习编程知识

    auto关键字

    auto简介

    在早期的C/C++中auto的含义是:使用auto修饰的变量是具有自动存储器的局部变量,但遗憾的是一直没有人去使用它。

    在C++11中,标准委员会赋予了auto全新的含义:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

    #include 
    using namespace std;
    double Fun()
    {
    	return 3.14;
    }
    int main()
    {
    	int a = 10;
    	auto b = a;
    	auto c = 'A';
    	auto d = Fun();
    	//打印变量b,c,d的类型
    	cout << typeid(b).name() << endl;//打印结果为int
    	cout << typeid(c).name() << endl;//打印结果为char
    	cout << typeid(d).name() << endl;//打印结果为double
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    测试结果:
    在这里插入图片描述

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

    auto的使用规则

    一、auto与指针和引用结合起来使用

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

    #include 
    using namespace std;
    int main()
    {
    	int a = 10;
    	auto b = &a;   //自动推导出b的类型为int*
    	auto* c = &a;  //自动推导出c的类型为int*
    	auto& d = a;   //自动推导出d的类型为int
    	//打印变量b,c,d的类型
    	 //typeid().name() 可以查看类型
    	cout << typeid(b).name() << endl;//打印结果为int*
    	cout << typeid(c).name() << endl;//打印结果为int*
    	cout << typeid(d).name() << endl;//打印结果为int
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试结果:
    在这里插入图片描述

    注意:用auto声明引用时必须加&,否则创建的只是与实体类型相同的普通变量。

    二、在同一行定义多个变量

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

    int main()
    {
    	auto a = 1, b = 2; //正确
    	auto c = 3, d = 4.0; //编译器报错:“auto”必须始终推导为同一类型
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    测试结果:
    在这里插入图片描述

    auto不能推到的场景

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

    以下代码编译失败,auto不能作为形参类型,因为编译器无法对x的实际类型进行推导。

    void TestAuto(auto x)
    {}
    
    • 1
    • 2

    在这里插入图片描述

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

    int main()
    {
    	int a[] = { 1, 2, 3 };
    	auto b[] = { 4, 5, 6 };//error
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

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

    范围for的语法

    若是在C++98中我们要遍历一个数组,可以按照以下方式:

    	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    	//将数组元素值全部乘以2
    	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    	{
    		arr[i] *= 2;
    	}
    	//打印数组中的所有元素
    	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    	{
    		cout << arr[i] << " ";
    	}
    	cout << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    以上方式也是我们C语言中所用的遍历数组的方式,但对于一个有范围的集合而言,循环是多余的,有时还容易犯错。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。

    	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    	//将数组元素值全部乘以2
    	for (auto& e : arr)
    	{
    		e *= 2;
    	}
    	//打印数组中的所有元素
         //依次取数组中的数据赋值给e
         //自定判断结束
         //自动迭代
    	for (auto e : arr)
    	{
    		cout << e << " ";
    	}
    	cout << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    范围for的使用条件

    一、for循环迭代的范围必须是确定的

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

    二、迭代的对象要实现++和==操作

    这就涉及到迭代器的问题,大家先了解一下就行。

    指针空值nullptr

    C++98中的指针空值

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

    int* p1 = NULL;
    int* p2 = 0;
    
    • 1
    • 2

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

    /* Define NULL pointer value */
    #ifndef NULL
    #ifdef __cplusplus
    #define NULL    0
    #else  /* __cplusplus */
    #define NULL    ((void *)0)
    #endif  /* __cplusplus */
    #endif  /* NULL */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    #include 
    using namespace std;
    void Fun(int p)
    {
    	cout << "Fun(int)" << endl;
    }
    void Fun(int* p)
    {
    	cout << "Fun(int*)" << endl;
    }
    int main()
    {
    	Fun(0);           //打印结果为 Fun(int)
    	Fun(NULL);        //打印结果为 Fun(int)
    	Fun((int*)NULL);  //打印结果为 Fun(int*)
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述
    程序本意本意是想通过Fun(NULL)调用指针版本的Fun(int* p)函数,但是由于NULL被定义为0,Fun(NULL)最终调用的是Fun(int p)函数。

    :在C++98中字面常量0,既可以是一个整型数字,也可以是无类型的指针(void*)常量,但编译器默认情况下将其看成是一个整型常量,如果要将其按照指针方式来使用,必须对其进行强制转换。

    C++11中的指针空值

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

  • 相关阅读:
    【目标检测算法】YOLO-V1~V3原理梳理
    Springboot 引入第三方jar包,并打包运行
    家居品牌如何在小红书上推广?家居产品推广看这里
    libcurl库的网页爬虫程序
    Photoshop图片处理
    实现物联网的技术要素
    Python顺序表
    ssm及springboot整合shiro
    CSS 圆角渐变边框
    CountDownLatch的使用
  • 原文地址:https://blog.csdn.net/weixin_72066135/article/details/133912138