【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)

简介: 【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值

【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)https://developer.aliyun.com/article/1617290

三、auto关键字(C++11)

3.1 类型别名思考

由于程序中使用到的类型也越来越复杂,导致了类型难于拼写,含义不明确导致容易出错。

比如:std::map::iterator类型但是该类型太长了,特别容易写错。这里可以考虑使用typedef为类型取别名typedef std::map::iterator Map。但是typedef本身存在不足。

3.2 typedef陷阱

typedef char * pstring;
int main()
{
    const pstring p1//编译成功还是失败?-->失败
    const pstring* p2//编译成功还是失败?-->成功
    return 0;
}

过程解析:这里const pstring != const char *由于const pstringconst赋予了整个指针本身常性,形成了常量指针char * const。对于p2来说,const pstring* p2转化后char* const p2,对于p2二级指针可以不初始化。

虽然 typedef 并不真正影响对象的存储特性,但在语法上它还是一个存储类的关键字,就像 auto、extern、static 和 register 等关键字一样。

typedef static int INT_STATIC;

由于typedef已经占据存储类关键字位置,因此typedef声明中就不能再使用static或任何其他存储类关键字,导致不能声明多个存储类关键字

3.3 auto简历

在早期C/C++中auto的含义是使用auto修饰的变量,该变量具有自动存储器的局部变量,但是没有人使用它,因为意义不大,这里指向的是局部变量,那么当函数结束,局部变量出了作用域,生命周期结束,变量会自动销毁,对此使用没有意义。

C++11中,auto被赋予了新的含义auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译中推导而得

int TestAuto()
{
    return 10;
}
int main()
{
    int a = 10;
    auto b = a;
    auto c = 'a';
    auto d = TestAuto();
    cout << typeid(b).name() << endl;
    cout << typeid(c).name() << endl;
    cout << typeid(d).name() << endl;
    //auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
    return 0;
}

打印变量类型:typeid(对象名).name()

3.4 auto使用(自动识别类型)

1. auto定义变量

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

2.auto与指针和引用结合起来使用

auto与指针和引用结合起来使用。当auto声明指针类型时,用auto和auto*没有任何区别(*如果使用auto ,则表示指向的变量是指针类型)但用auto声明引用类型时,则必须加&

int main()
{
    int x = 10;
    auto a = &x;
    auto* b = &x;
    auto& c = x;
    cout << typeid(a).name() << endl;
    cout << typeid(b).name() << endl;
    cout << typeid(c).name() << endl;
    *a = 20;
    *b = 30;
    c = 40;
    return 0;
}

3.auto在同一行定义多个变量

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

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

3.5 auto不能推导场景

1.auto不能作为函数参数

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

auto虽然不能作为函数参数,但是可以做函数返回值。对于auto作为函数返回值的建议是慎用,可能使得可读性下降。

如果多层嵌套函数返回值类型是auto,想要得到具体的返回值的类型,需要一个个函数去检查。

auto TestAuto(int a)
{
  return a;
}

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

void TestAuto()
{
    int a[] = {1,2,3};
    auto b[] = {4,5,6};
}

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

3.1 范围for语法

对于一个有范围的集合而言,交给程序员来说明循环范围是多余的,可能还会导致犯错误。对此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来跳出整个循环

3.2 范围for的使用条件

1.for循环迭代的范围必须是确定的

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

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

void TestFor(int array[])
{
    for(auto& e : array)
        cout<< e <<endl;
}

2. 迭代的对象需要要实现++和==的操作(本质还是迭代器)

四、指针空值

在C/C+良好的编程习惯中,对于未初始化的指针,一个没有合法的指向的指针,基本会进行初始化。int *p=NULL\0。对此在C头文件中,可知NULL实际是一个宏。

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

对此NULL可能定义有两种(字面常量0,无类型指针(void)的常量)*,C++中使用NULL指针空值,可能会遇到一些问题。

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

按照预期,传NULL应该调用int *的函数,但是NULL被定义成0.对此预期和结果不匹配。对此为了区分C++和C,C++引出了nullptr关键字代替NULL的使用。

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

小结:

  1. nullptr是C++11作为新关键字引入的,在使用过程中,不需要包含头文件
  2. 在C++11中,sizeof(nullptr)sizeof((void *)0)所占的字节数相同
  3. 为了提高代码的健壮性,在后续C++使用中最好使用nullptr表示指针空值

以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二呀C++笔记,希望对你在学习C++语言旅途中有所帮助!

相关文章
|
14天前
|
安全 编译器 程序员
C++ noexcept 关键字的关键作用
`noexcept` 关键字在 C++ 中扮演着重要角色,通过正确使用 `noexcept`,可以提升程序的性能、增强代码的可读性和安全性,并且有助于编译器进行优化。在编写 C++ 代码时,应仔细考虑每个函数是否应该声明为 `noexcept`,以充分利用这一特性带来的优势。通过本文的介绍,希望开发者能够更好地理解和应用 `noexcept` 关键字,从而编写出更加高效、健壮的 C++ 程序。
27 8
|
3月前
|
安全 编译器 C++
C++ `noexcept` 关键字的深入解析
`noexcept` 关键字在 C++ 中用于指示函数不会抛出异常,有助于编译器优化和提高程序的可靠性。它可以减少代码大小、提高执行效率,并增强程序的稳定性和可预测性。`noexcept` 还可以影响函数重载和模板特化的决策。使用时需谨慎,确保函数确实不会抛出异常,否则可能导致程序崩溃。通过合理使用 `noexcept`,开发者可以编写出更高效、更可靠的 C++ 代码。
79 1
|
4月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
337 13
|
9月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
5月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
65 0
|
6月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
219 4
|
7月前
|
C语言
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
|
7月前
|
C语言
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)
|
7月前
|
存储 编译器 C语言
【C初阶——指针3】鹏哥C语言系列文章,基本语法知识全面讲解——指针(3)
【C初阶——指针3】鹏哥C语言系列文章,基本语法知识全面讲解——指针(3)
|
8月前
|
编译器 C语言
【C语言初阶】指针篇—下
【C语言初阶】指针篇—下