【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。

相关文章
|
6月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
262 0
|
10月前
|
安全 编译器 程序员
C++ noexcept 关键字的关键作用
`noexcept` 关键字在 C++ 中扮演着重要角色,通过正确使用 `noexcept`,可以提升程序的性能、增强代码的可读性和安全性,并且有助于编译器进行优化。在编写 C++ 代码时,应仔细考虑每个函数是否应该声明为 `noexcept`,以充分利用这一特性带来的优势。通过本文的介绍,希望开发者能够更好地理解和应用 `noexcept` 关键字,从而编写出更加高效、健壮的 C++ 程序。
328 8
|
12月前
|
安全 编译器 C++
C++ `noexcept` 关键字的深入解析
`noexcept` 关键字在 C++ 中用于指示函数不会抛出异常,有助于编译器优化和提高程序的可靠性。它可以减少代码大小、提高执行效率,并增强程序的稳定性和可预测性。`noexcept` 还可以影响函数重载和模板特化的决策。使用时需谨慎,确保函数确实不会抛出异常,否则可能导致程序崩溃。通过合理使用 `noexcept`,开发者可以编写出更高效、更可靠的 C++ 代码。
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
208 1
|
程序员 C++
C++编程:While与For循环的流程控制全解析
总结而言,`while`循环和 `for`循环各有千秋,它们在C++编程中扮演着重要的角色。选择哪一种循环结构应根据具体的应用场景、循环逻辑的复杂性以及个人的编程风格偏好来决定。理解这些循环结构的内在机制和它们之间的差异,对于编写高效、易于维护的代码至关重要。
511 1
|
存储 编译器 程序员
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
167 0
|
存储 安全 编译器
C++入门 | auto关键字、范围for、指针空值nullptr
C++入门 | auto关键字、范围for、指针空值nullptr
290 4
|
存储 程序员 C++
【C++小知识】基于范围的for循环(C++11)
【C++小知识】基于范围的for循环(C++11)
|
编译器 C语言 C++
【C++关键字】指针空值nullptr(C++11)
【C++关键字】指针空值nullptr(C++11)
|
存储 编译器 C++
【C++关键字】auto的使用(C++11)
【C++关键字】auto的使用(C++11)