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

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

auto关键字

auto简介

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

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

#include <iostream>
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;
}

测试结果:

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

auto的使用规则

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

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

#include <iostream>
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;
}

测试结果:

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

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

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

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

测试结果:

auto不能推到的场景

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

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

void TestAuto(auto x)
{}

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

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

基于范围的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;

以上方式也是我们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;

范围for的使用条件

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

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

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

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

指针空值nullptr

C++98中的指针空值

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

int* p1 = NULL;
int* p2 = 0;

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 */

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

#include <iostream>
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;
}

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

相关文章
|
1月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
1月前
|
程序员 C++
C++编程:While与For循环的流程控制全解析
总结而言,`while`循环和 `for`循环各有千秋,它们在C++编程中扮演着重要的角色。选择哪一种循环结构应根据具体的应用场景、循环逻辑的复杂性以及个人的编程风格偏好来决定。理解这些循环结构的内在机制和它们之间的差异,对于编写高效、易于维护的代码至关重要。
54 1
|
1月前
|
存储 编译器 程序员
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
3月前
|
存储 程序员 C++
【C++小知识】基于范围的for循环(C++11)
【C++小知识】基于范围的for循环(C++11)
|
4月前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
|
5月前
|
存储 安全 编译器
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
66 5
|
5月前
|
存储 编译器 C++
【C++ 初阶路】--- 类和对象(下)
【C++ 初阶路】--- 类和对象(下)
24 1
|
5月前
|
存储 编译器 C语言
【C++初阶路】--- 类和对象(中)
【C++初阶路】--- 类和对象(中)
28 1
|
5月前
|
安全 编译器 程序员
【C++初阶】--- C++入门(上)
【C++初阶】--- C++入门(上)
33 1
|
4月前
|
存储 编译器 C++
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么