目录
8. auto关键字
8.1 auto简介
8.2 auto的使用细节
8.3 auto不能推导的场景
9. 基于范围的for循环
9.1 范围for循环的语法
10. 指针空值nullptr
10.1 C++中的指针空值
8. auto关键字
8.1 auto简介
在C++11之前的版本中,对于auto的概念仅仅只有被auto修饰的变量,是具有自动存储器的局部变量。
在C++11版本中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
这是什么意思呢?
我们可以看见b的类型最终转变成了int。
当auto定义的变量没有初始化时,则会对其报错,是因为在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。
对于auto我们可以认为它可以帮助我们在定义变量时不需要写一些比较复杂的类型名,通过auto来直接替换
8.2 auto的使用细节
1. auto对于指针和引用结合使用
我们可以看见当右值是指针时,auto和auto*没有任何区别,但auto要声明引用时必须加上&,否则会认为是一个简单的替换实际类型。
2. auto定义一行
我们可以发现其实auto关键字修饰的变量的类型就是右值的类型,因此我们定义的每一行的右值类型也需要保持一致
否则会产生这样的错误。
8.3 auto不能推导的场景
1. auto不能作为函数的参数
因为你不知道这个10应该转成什么类型,会产生歧义,所以编译器直接禁止了在参数包含auto类型。
2. auto不能直接用来声明数组
同理我们也不知道这个auto应该转成什么类型,也会产生歧义,因此编译器也禁用了在数组中使用auto类型。
9. 基于范围的for循环
9.1 范围for循环的语法
在C++98之前的版本如果我们需要遍历一个数组我们需要:
void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
// 1. 下标访问
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
array[i] *= 2;
// 2. 指针访问
for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p)
cout << *p << endl;
}
这样对于一个程序员来说,说明一个数组的范围有点多余,因此我们在C++11版本中引入了基于范围for循环的语法,for循环括号中用":"分成了两个部分:第一部分是范围内用于迭代的变量, 第二部分则表示被迭代的范围。
范围for循环也类似于普通循环,遇见break和continue也会执行相同的操作。
当然e之前的auto也可以替换成数组的类型,只不过auto增加了代码的灵活性。
那如果我们要通过e来改变数组中的元素呢?
我们发现当e++后数组却没有发生改变,这是为什么呢?
因为范围for循环只是把数组中的值赋给了e,e中的改变对于数组是没有任何影响的,那我们如何改变数组中的值呢?这里我们就用到了引用(&)。
加上引用后e就相当于是数组中每个值的别名,对于别名的修改也就是对本身的修改。
10. 指针空值nullptr
10.1 C++中的指针空值
在C/C++编程中,对于一个变量的定义我们需要给它一个合适的初始值,否则就会产生不可预料的问题,一般来说我们都是这样初始化的:
int main(){
int a=0;
int*p=NULL;
return 0;
}
对于NULL,在定义中其实是一个宏:
可以看到,NULL可能被定义为字面常量0,也可能被定义为无类型指针((void*)0)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:
我们的本意是将NULL看做一个指针调用f(int*),但在这里将NULL看成了一个数值,与程序的初衷相悖。
在C++98版本中0既可以代表一个数值也可以代表一个void*指针,但一般情况下编译器会将其识别成为一个数值,如果要代表成一个指针时,需要对其进行强制转换。
因此在C++11版本中我们引入了一个新的空指针 - nullptr。
注意:
1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11版本中作为新关键字引入的。
2. 在C++11版本中,nullptr就是(void*)0,因此sizeof(nullptr)==sizeof((void*)0)
继续努力!



