C++:关键字“auto“详解,“范围for“讲解,NULL-0-nullptr 三者区分

目录

一.auto关键字(C++11)

1.auto简介

2.作用:用于推导变量的类型

3. auto的使用细则

4.auto真正的意义

(1)类型很长时,懒得写,可以让他自动推导

(2)范围for

 范围for的几个小细节:

5.auto不能推导的场景(以下全是错误示例)

(1)auto不能作为参数,缺省参数也不行

(2)auto不能定义时不初始化

(3)auto不能作返回值(为了防止滥用auto)

(4)auto不能直接用来声明数组(了解以下即可)

6.auto用法总结

二.NULL——0——nullptr 三者区分

1.NULL的详细解释:

 2.nullptr详细解释


一.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
  • 15
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
要反转一个单链表,你可以按照以下步骤进行: 1. 定义三个指针:prev(前一个节点)、current(当前节点)和next(下一个节点)。 2. 初始化 prev 为 nullptr,current 为链表的头节点。 3. 遍历链表,将 current 的 next 指针指向 prev,然后更新 prev、current 和 next 分别为 current、next 和 next->next。 4. 重复步骤 3,直到遍历完整个链表。 5. 最后,将链表的头节点指向 prev。 下面是一个示例的 C++ 代码实现: ```cpp #include <iostream> struct Node { int data; Node* next; }; // 在链表末尾添加新节点 void appendNode(Node** head, int newData) { Node* newNode = new Node(); newNode->data = newData; newNode->next = nullptr; if (*head == nullptr) { *head = newNode; return; } Node* temp = *head; while (temp->next != nullptr) { temp = temp->next; } temp->next = newNode; } // 反转链表 Node* reverseList(Node* head) { Node* prev = nullptr; Node* current = head; Node* next = nullptr; while (current != nullptr) { next = current->next; current->next = prev; prev = current; current = next; } return prev; } // 打印链表 void printList(Node* head) { Node* temp = head; while (temp != nullptr) { std::cout << temp->data << " "; temp = temp->next; } std::cout << std::endl; } int main() { Node* head = nullptr; // 添加一些节点 appendNode(&head, 1); appendNode(&head, 2); appendNode(&head, 3); appendNode(&head, 4); appendNode(&head, 5); std::cout << "原始链表: "; printList(head); head = reverseList(head); std::cout << "反转后的链表: "; printList(head); return 0; } ``` 代码中的 `reverseList` 函数使用了三个指针 prev、current 和 next 来反转链表。我们使用一个 while 循环遍历链表,每次迭代将 current 的 next 指针指向 prev,然后更新 prev、current 和 next 的值。最后,我们返回 prev,作为反转后的链表的头节点。 在 `main` 函数中,我们创建了一个示例链表,然后调用 `reverseList` 函数来反转链表,并打印结果。 希望对你有所帮助!如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值