目录
一.auto关键字(C++11)
1.auto简介
在早期
C/C++
中
auto
的含义是:使用
auto
修饰的变量,是具有自动存储器的局部变量
,但遗憾的是一直没有
人去使用它,大家可思考下为什么?
C++11
中,标准委员会赋予了
auto
全新的含义即:
auto
不再是一个存储类型指示符,而是作为一个新的类型
指示符来指示编译器,
auto
声明的变量必须由编译器在编译时期推导而得
。
2.作用:用于推导变量的类型
使用
auto
定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导
auto
的实际类
型
。因此
auto
并非是一种
“
类型
”
的声明,而是一个类型声明时的
“
占位符
”
,编译器在编译期会将
auto
替换为
变量实际的类型
。
举例说明:
利用一个用法
typeid(变量).name()
用于打印一个变量的类型,typeid(变量).name() 返回的是类型的字符串(结构体这些自定义类型也可以)
3. auto的使用细则
(1).
auto
与指针和引用结合起来使用
用
auto
声明指针类型时,用
auto
和
auto*
没有任何区别,但用
auto
声明引用类型时则必须加
&
(2). 在同一行定义多个变量
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对
第一个类型进行推导,然后用推导出来的类型定义其他变量
。
void TestAuto()
{
auto a = 1, b = 2;
auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}
4.auto真正的意义
(1)类型很长时,懒得写,可以让他自动推导
下面的代码std::map<std::string, std::string>::iterator 这个类型很长,不如用auto代替
#include<iostream>
using namespace std;
#include <map>
#include <string>
int main()
{
//auto x;
std::map<std::string, std::string> dict;
dict["sort"] = "排序";
dict["string"] = "字符串";
// auto意义之一:类型很长时,懒得写,可以让他自动推导
std::map<std::string, std::string>::iterator it = dict.begin();
//不如写成 auto it = dict.begin();
return 0;
}
(2)范围for
概念:
对于一个
有范围的集合
而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此
C++11
中引入了基于范围的for
循环。
for
循环后的括号由冒号
“
:
”
分为两部分:第一部分是范围内用于迭代的变量,
第二部分则表示被迭代的范围
。
用范围for打印数组
int main()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
{
array[i] *= 2;
}
for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
{
cout << array[i] << " ";
}
cout << endl;
//上面是正常乘2打印数组,下面是范围for打印数组
// 范围for
// 依次自动取array中的数据,赋值给e,自动判断结束
for (auto e : array)
{
cout << e << " ";
}
cout << endl;
return 0;
}
如果用范围for改变数组内容需要加引用
int main()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
{
array[i] *= 2;
}
for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
{
cout << array[i] << " ";
}
cout << endl;
// 范围for
// 依次自动取array中的数据,赋值给e,自动判断结束
for (auto& e : array)
{
e/=2; //想要改变数组内的值,需要auto&,如果只用auto仅仅是拷贝
}
for (auto e : array)
{
cout << e << " ";
}
cout << endl;
return 0;
}
范围for的几个小细节:
【1】e是单词元素element首字母,可以改成其他的字母表示
不一定只用auto,普通类型也可以,只是用了auto无论数组里什么类型都可以接收
(1)
for (auto& e : array)
{
e/=2; //e是单词元素element首字母,可以改成其他的字母表示
// x/=2; 也可以
}
(2)
//这里不一定只用auto,普通类型也可以,只是用了auto无论数组里什么类型都可以接收
for (int e : array)
{
e/=2;
}
【2】for循环迭代的范围必须是确定的
对于数组而言,就是数组中第一个元素和最后一个元素的范围
;对于类而言,应该提供
begin
和
end
的
方法,
begin
和
end
就是
for
循环迭代的范围。
注意:以下代码就有问题,因为
for
的范围不确定,
因为形式参数中的array已经成为了指针
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <<endl; }
5.auto不能推导的场景(以下全是错误示例)
(1)auto不能作为参数,缺省参数也不行
错误
此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}
错误
void TestAuto(auto a=10)
{}
(2)auto不能定义时不初始化
错误!!
auto x;
(3)auto不能作返回值(为了防止滥用auto)
错误
auto Test()
{
return 10;
}
(4)auto不能直接用来声明数组(了解以下即可)
错误
void TestAuto()
{
int a[] = {1,2,3};
auto b[] = {4,5,6};
}
6.auto用法总结
最常用还是普通定义变量和范围for的使用
二.NULL——0——nullptr 三者区分
NULL,0,nullptr值都是0,但是类型不同,但是由于C头文件中NULL定义宏混乱,可能是int 0,也可能是(void*)0,所以我们在C++引入新的空指针nullptr,nullptr就是(void*)0,所以我们在C++中空指针统一用nullptr
1.NULL的详细解释:
NULL
实际是一个宏,在传统的
C
头文件
(stddef.h)
中,可以看到如下代码:
可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何种定义,在 使用空值的指针时,都不可避免的会遇到一些麻烦
利用函数重载证明NULL和0是是整形0,nullptr是(void*)0:
void f(int) {
cout << "f(int)" << endl;
}
void f(int*) {
cout << "f(int*)" << endl;
}
int main()
{
f(0); //调用了void f(int)
f(NULL); //调用了void f(int)
f(nullptr); //调用了void f(int*)
return 0;
}
2.nullptr详细解释
1.
在使用nullptr
表示指针空值时,不需要包含头文件,因为
nullptr
是
C++11
作为新关键字引入的
。
2.
在
C++11
中,
sizeof(nullptr)
与
sizeof((void*)0)
所占的字节数相同。
3.
为了提高代码的健壮性,在后续表示指针空值时建议最好使用
nullptr
。