2024年最新万丈高楼平地起——C++入门(下卷,2024年最新重磅来袭

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

(4)普通引用引用常变量。(非法操作)

下面操作是非法的:

int& ib = b;

总结:

取别名的原则:对原引用变量,权限只能缩小,不能放大。

在上面的例子中,(2)就是权限的缩小,变量a是可读可写的,但是引用ia就是只能读的了,所以就是权限;(4)就是权限的放大,常变量b是只读的,但是引用ib是可读可写的,所以这就是权限的扩大。

💘6.3.2 注意点

(1)常引用可以对常量取别名。

const int& a = 100;

此时的权限既没有扩大也没有缩小,因为a的权限就是只读的,100作为常量的权限也是只读的。

(2)引用的类型都要和与之绑定的对象严格匹配。

double d = 3.14;
int& id = d;

此处的引用是非法操作,引用类型的初始值必须是int型对象。

但是在int的前面加上一个const就可以了,如下操作:

const int& id = d;

我们知道,在将double类型的变量赋值给int型时,会发生隐式类型转换:

double pi = 3.14;
int a = pi;

在将pi赋值给变量a的过程中,实际上发生了一个类型转换,即3.14被转换成int类型发生了截断,这个过程中会有一个临时变量来存储3.14这个值,存储位置一般是寄存器,下面用图来表示:

image-20220510184758376

double d = 3.14;
const int& id = d;

此处ri引用了一个int型的数,对ri得操作应该是整数运算,但d却是一个双精度浮点数而非整数,因此为了让id绑定一个整数,编译器把上述代码变成了如下形式:

const int temp = d;//由双精度浮点数生成一个临时的整型常量
const int& id = temp;//由id绑定这个临时量

在这种情况下,id绑定了一个临时量对象。所谓临时量对象就是当编译器需要一个空间(寄存器或内存空间)来暂存表达式临时创建的一个未命名的对象。C++程序员常常把临时对象称为临时量。

临时变量具有常性,是只读常量,所以能被const进行引用,如果没有const,就属于权限的放大。

注意:在将寄存器中的3赋值给3的过程中,本质上还是值的拷贝,即将寄存器中3的二进制位拷贝到变量a的内存空间中,对变量a进行修改,寄存器中的值不会有所改变,引用亦是如此。

当然,还有另外一种理解(只作为理解):

问:pi作为右值时代表的是什么?

答:pi作为右值时就是pi变量空间中存储的值,所以上面的代码就相当于是下面这段代码:

const int& a = 3.14;

3.14是只读常量,因为左边的类型是const int&,所以发生了强制类型转换,变成了3,3作为临时变量具有常性,所以能够被赋值给a。

注意:普通对象不存在权限的放大与缩小的问题,如我们通常使用的赋值表达式int a = 3,a只是一个普通变量,只是将3的二进制位拷贝到变量a所在的内存空间中,所以不存在权限的放大与缩小的问题。因为a的改变不会改变10,只有指针和引用才会存在权限的放大与缩小的问题。

💞6.4 使用场景

  1. 做参数
void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}
int main()
{
    int a = 10;
    int b = 20;
    Swap(a,b);//实现了变量a和b的交换,交换之后a的值位20,b的值为10
    return 0;
}

意义:

  • 一定程度上规避指针,使代码更容易理解
  • 减少值拷贝,提高效率
  1. 做返回值

首先先看下面的一段代码:

int& Count()
{
	static int n = 0;
	n++;
	return n;
}
int main()
{
    cout << Count() << endl;
    cout << Count() << endl;
    cout << Count() << endl;
    return 0;
}

上面的输出结果是123,因为n是静态全局变量,存储在静态区,声明周期在整个程序运行期间始终存在,且静态全局变量只初始化一次,所以只运行一次static int n = 0,所以输出结果是123。

下面看这段代码:

int Count()
{
    static int n = 0;
    n++;
    return n;
}
int main()
{
    int ret = Count();
    return 0;
}

注意:无论是函数在进行传参还是函数在传返回值的时候,都会形成一个临时变量,如果所传的参数或返回值较小,那么临时变量就用寄存器进行传递,否则就不用寄存器替代。

问:为什么要出现一个临时变量?

答:如果没有临时变量,在Count()函数调用结束之后,函数栈帧就销毁了,n所在的内存空间就无法使用了,所以就无法将返回值进行返回。

但是如果我们将n的值放在一个临时变量中,这个临时变量可能是寄存器,也有可能是内存中的某一个空间(比如在调用Count()函数之前提前在main()函数中开辟好要存储返回值的空间),但无论如何,这个临时变量都已经不在Count()函数的栈帧上了,所以我们可以在Count()函数栈帧销毁之后依然可以将n的值传递回main函数中。

那么传值返回的意义是什么呢?意义就是临时变量的类型是int类型。

此时看下面这段代码:

int Count()
{
    int n = 0;
    n++;
    return n;
}
int main()
{
    const int& ret = Count();
    return 0;
}

这个程序可以正常运行,为什么呢?因为return n传递的临时变量具有常性,可以被常引用接收,实际上上面这段代码类似于const int& ret = 1

再看下面这段代码:

int& Count()
{
    int n = 0;
    n++;
    return n;
}
int main()
{
    int ret = Count();
    return 0;
}

上面这段代码是什么意思呢?表示return返回的临时变量的类型是int&,这个引用是Count()栈帧中变量n的引用或者别名。

总结:如果返回类型是int,那么临时变量就是返回值的临时拷贝,类型就是int,如果返回类型是int&,那么临时变量就是被调用函数栈帧中所要传变量的引用。

再看下面这段代码:

int& Count()
{
    int n = 0;
    n++;
    return n;//返回的是n的别名
}
int main()
{
    int& ret = Count();
    return 0;
}

临时变量的类型是int&类型,所以也能被int&类型的ret来接收。

return n,返回的是n的别名,又将n的别名赋值给ret,即ret是别名的别名,就是n的别名。

采用如下方式进行验证:

int& Count()
{
    int n = 0;
    n++;
    cout << "Count:" << &n << endl;
    return n;
}
int main()
{
    int& ret = Count();
    cout << "main:" << &ret << endl;
    return 0;
}

运行结果:

image-20220510220222171

ret和n的地址是一样的,说明ret就是n的别名。

传值返回和传引用返回有什么区别?

传值返回:会有一个拷贝。

传引用返回:没有拷贝,函数返回的直接就是返回变量的别名。

问:上面例子中的Count栈帧已经销毁了,为什么还存在n的别名?我们甚至还能在main函数中访问到n?

答:函数栈帧的销毁只是我们不再拥有那段空间的使用权,那段空间依旧存在,我们依然可以通过引用或者指针去访问它,但是那段空间一旦被其它的函数栈帧所覆盖,那么我们再次进行访问输出,得到的就是一个随机值。如下面的代码所示:

int& Count()
{
    int n = 0;
    n++;
    return n;
}
int main()
{
    int& ret = Count();
    cout << ret << endl;
    cout << ret << endl;
    cout << ret << endl;
    return 0;
}

运行结果:

image-20220510223117657

在第一次输出正确结果的原因是因为原来的栈帧销毁后内存空间中的值并没有改变,当然,这种行为是非法的,类似野指针,后面两次输出结果错误是因为cout调用了函数,栈帧被覆盖了,所以输出结果就是随机值。

问:什么场景下可以用引用返回来减少拷贝?什么时候只能用传值返回?

答:如果函数返回时,出了函数作用域,如果返回对象还未还给系统(例如static变量或者全局变量),则可以使用引用返回,如果已 经还给系统了,则必须使用传值返回。

此时看下面这段代码:

int& Add(int a, int b)
{
    int c = a + b;
    return c;
}
int main()
{
    int& ret = Add(1,2);
    Add(3,4);
    cout << "Add(1,2) is :" << ret << endl;
    return 0;
}

输出结果:

image-20220510230746090

出现7的结果如下:

ret是Add函数中局部变量c的别名,虽然在函数Add(1,2)调用之后销毁了,但是值仍然保存在那,通过ret仍然能够找到那块空间,再次调用Add(3,4)那个函数,c变量的那段空间所存储的值变成了7,这就是输出结果为7的原因。当然,如果我们像下面这样进行修改代码,就会出现不是7而是随机数的结果:

int& Add(int a, int b)
{
    int c = a + b;
    return c;
}
int main()
{
    int& ret = Add(1, 2);
    Add(3, 4);
    cout << "Add(1,2) is :" << ret << endl;
    cout << "Add(1,2) is :" << ret << endl;
    return 0;
}

输出结果:

image-20220511085645057

第二次输出结果就是随机数了,原因就是之前Add所在的栈帧空间因为第一次cout相关函数的调用栈帧被覆盖了,所以会输出随机数。

如果我们继续像下面这样修改代码,就会出现不一样的结果:

int& Add(int a, int b)
{
    static int c = a + b;
    return c;
}
int main()
{
    int& ret = Add(1, 2);
    Add(3, 4);
    cout << "Add(1,2) is :" << ret << endl;
    cout << "Add(1,2) is :" << ret << endl;
    return 0;
}

输出结果:

image-20220511085919433

因为static变量是存在于静态区的,生命周期是整个程序的运行期间,会一直存在,所以输出结果为3,且再次进行打印也会输出同样的结果。

💞6.5 传值、传引用传指针效率比较

💘6.5.1 传值、传引用传指针作为参数效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是 传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestFunc3(A\*) {}
void TestRefAndValue()
{
	A a;
	// 以值作为函数参数
	size_t begin1 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc1(a);
	size_t end1 = clock();
	// 以引用作为函数参数
	size_t begin2 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc2(a);
	size_t end2 = clock();
	//以指针作为函数参数
	size_t begin3 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc3(&a);
	size_t end3 = clock();
	// 分别计算两个函数运行结束后的时间
	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
	cout << "TestFunc3(&A)-time:" << end3 - begin3 << endl;
}
int main()
{
	TestRefAndValue();
	return 0;
}

运行结果:

image-20220510204604698

从上图中可以看出,传指针和传引用比传值效率高很多。

💘6.5.2 传值、传引用传指针作为返回值返回效率比较

代码:

#include <time.h>
struct A { int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a; }
// 引用返回
A& TestFunc2() { return a; }
A\* TestFunc3(){ return &a; }
void TestReturnByRefOrValue()
{
	// 以值作为函数的返回值类型
	size_t begin1 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc1();
	size_t end1 = clock();
	// 以引用作为函数的返回值类型
	size_t begin2 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc2();
	size_t end2 = clock();
    //以指针作为函数的返回类型
	size_t begin3 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc3();
	size_t end3 = clock();
	// 计算两个函数运算完成之后的时间
	cout << "TestFunc1 time:" << end1 - begin1 << endl;
	cout << "TestFunc2 time:" << end2 - begin2 << endl;
	cout << "TestFunc3 time:" << end3 - begin3 << endl;
}
int main()
{
	TestReturnByRefOrValue();
	return 0;
}

运行截图:

image-20220511091244023

通过上述代码的比较,发现传值和指针或引用在作为传参以及返回值类型上效率相差很大,传指针和传引用的的效率相差不大。

💞6.6 引用和指针的区别

语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

int main()
{
	int a = 10;
	int& ra = a;

	cout << "&a = " << &a << endl;
	cout << "&ra = " << &ra << endl;
	return 0;
}

底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

int main()
{
	int a = 10;

	int& ra = a;
	ra = 20;

	int\* pa = &a;
	\*pa = 20;

	return 0;
}

引用和指针的汇编代码比较:

image-20220511093015613

可以看到两者的汇编代码是一样的,所以它们的底层实现是一模一样的。

指针和引用赋值的汇编代码比较:

image-20220511094413630

使用指针和使用引用进行赋值从汇编代码上看,它们也是完全一样的。

引用和指针的不同点:

  1. 引用在定义时必须初始化,指针没有要求
  2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型 实体
  3. 没有NULL引用,但有NULL指针
  4. 在sizeof中含义不同引用结果为引用类型或者说是引用变量的大小,但指针始终是**地址空间所占字节个数(**32位平台下占 4个字节)
  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  6. 有多级指针但是没有多级引用
  7. 访问实体方式不同,指针需要显式解引用引用编译器自己处理
  8. 引用比指针使用起来相对更安全
  9. 从语法上来说,引用并没有开辟额外的空间,只是一个别名,指针开辟了空间,存储地址;但从底层上来说,引用和指针一样,开辟了空间存放地址。

💓7. 内联函数

💞7.1 概念

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销, 内联函数提升程序运行的效率。

为什么要出现inline?

解决宏函数晦涩难懂,容易写错的问题,因为要考虑到优先级问题,所以要加很多的括号;另一方面宏不支持调试,并且没有类型安全的检查等问题,使用内联函数能够解决上面的问题。

image-20220511161852244

如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。

如果使用了内联函数,如下面代码所示:

inline int Add(int left, int right)
{
	return left + right;
}
int main()
{
	int ret = 0;
	ret = Add(1, 2);
	return 0;
}

在汇编语言查看时将不会看到call调用Add()函数。

使用inline后查看方式如下:

  1. 在release模式下,查看编译器生成的汇编代码中是否存在call Add,查看结果如下:(注:默认的debug版本下内联函数不会展开,但在release版本下会展开)
    image-20220511163321449
    发现在release版本下无法查看汇编代码。
  2. 在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不会对代码进 行优化,以下给出vs2019的设置方式)
    1. 右击项目工程,点击属性。
      image-20220511163846479
    2. 如下操作:
      image-20220511164508252
    3. 如下操作:
      image-20220511164152187

上述操作完成后查看反汇编:

image-20220511164654293

此时inline内联函数就实现了展开,没有了call汇编指令,即函数的调用。

💞7.2 特性

  1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长(一般10行以上就算长)或者有循环/递归的函数不适宜 使用作为内联函数。
  2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等 等,编译器优化时会忽略掉内联。
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline函数被展开,符号表里就没有对应的函数地址了,链接就会找不到。
// Func.h
#include <iostream>
using namespace std;
inline void func(int i);
// Func.cpp
#include "Func.h"
inline void func(int i)
{
	cout << i << endl;
}
// main.cpp
#include "Func.h"
int main()
{
	func(10);
	return 0;
}

这样程序会出现链接错误。

程序像下面这样进行修改就不会出现问题:

// Func.h
#include <iostream>
using namespace std;
inline void func(int i);
#include "Func.h"
void func(int i)
{
	cout << i << endl;
}
// main.cpp
#include "Func.h"
int main()
{
	func(10);
	return 0;
}

因为Func.h文件里的文本内容会在main.cpp文件中展开,所以不会出现链接错误。

当然,下面还有两种特殊的情况:

(1)声明的时候带inline,定义的时候不带inline

// Func.h
#include <iostream>
using namespace std;
inline void func(int i);
// Func.cpp
#include "Func.h"
void func(int i)
{
	cout << i << endl;
}
// main.cpp
#include "Func.h"
int main()
{
	func(10);
	return 0;
}

此时程序可以正常运行,没有出现链接错误,此时inline并没有发挥应有的作用,func函数并没有展开。

(2)声明的时候不带inline,定义的时候带inline。

// Func.h
#include <iostream>
using namespace std;
void func(int i);
// Func.cpp
#include "Func.h"
inline void func(int i)
{
	cout << i << endl;
}
// main.cpp
#include "Func.h"
int main()
{
	func(10);
	return 0;
}

此时程序不能正常运行,出现链接错误,因为Func.cpp文件汇编形成的符号表里依旧没有func函数的地址,所以会链接失败。

注意:如果在函数定义中加了inline,那么在函数声明中就可以不必再加了,这样也能达到inline的使用效果。

💞7.3 关联面试题

宏的优缺点?

优点:

  1. 增强代码的复用性。
  2. 提高性能。

缺点:

  1. 不方便调试宏。(因为预编译阶段进行了替换)
  2. 导致代码可读性差,可维护性差,容易误用。
  3. 没有类型安全的检查 。

C++有哪些技术替代宏?

  1. 常量定义 换用const
  2. 函数定义 换用内联函数

💓8. auto关键字(C++11)

在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量。

C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型 指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

补充知识:typeid().name函数可以用来让编译器告知某个变量的类型是什么,该函数的返回类型是一个字符串。

int TestAuto()
{
	return 10;
}
int main()
{
	int a = 10;
	auto b = a;//a是整型,编译器推导出变量b的类型是int型
	auto c = 'a';//'a'是字符型,编译器推导出变量c的类型是char类型
	auto d = TestAuto();//TestAuto函数的返回类型是int型,编译器推导出变量d的类型是int型
    const int e = 10;
    auto ie = &e;

	cout << typeid(b).name() << endl;//输出结果为int
	cout << typeid(c).name() << endl;//输出结果为char
	cout << typeid(d).name() << endl;//输出结果为int
	cout << typeid(ie).name() << endl;//输出结果为const int \* 

	//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
	return 0;
}

【注意】

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

💞8.2 auto的使用细则

  1. auto与指针和引用结合起来使用 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
int a = 10;
auto\* pa = &a;//指定pa为指针类型
auto\* ppa = &pa;
auto& ia = a;//指定ia的类型为引用类型
auto\* pa = a;//程序非法,因为指定了pa的类型是指针类型,但是我们却给它赋了地址
cout << typeid(pa).name() << endl;//输出结果为int \*
cout << typeid(ppa).name() << endl;//输出结果为int \*\*
cout << typeid(ia).name() << endl;//输出结果为int

  1. 在同一行定义多个变量
    当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对 第一个类型进行推导,然后用推导出来的类型定义其他变量。
auto a = 10, d = 3.14;//错误的使用方式
auto i = 0, \*p = &i;//正确的使用方式,i是整数,p是整型指针
auto a = 10, b = 20;//正确的使用方式,因为经过编译器推导之后,程序会变成下面的定义方式
int a = 10, b = 20;

  1. auto在使用时会遵循隐式类型转换的规则。比如下面这样:
int main()
{
	auto a = 3.14 + 5;//表达式3.14和5相加后的类型转换为double类型,值为8.14
	cout << typeid(a).name() << endl;
	return 0;
}

8.3 auto不能推导的场景

  1. auto不能作为函数的参数和返回值
// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto1(auto a)//注意:auto也不能作为缺省参数,例如:void TestAuto1(auto a = 10) {}
{}
auto TestAuto2(int a)
{}

问:为什么会存在这种限制呢?

答:因为我们要把相应的一些函数接口暴露出来给用户的,用户需要知道如何使用,需要传什么样的参数,需要什么样的变量来接收返回值,而且函数的参数和返回值都是auto的话,函数的可读性就不太好了,并且也会加大编译器的工作量。

  1. auto不能直接用来声明数组
void TestAuto()
{
	int a[] = {1,2,3};
	auto b[] = {4,5,6};
}

  1. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
  2. auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等 进行配合使用。

💞8.4 auto的意义

程序员不必再写出冗长的数据类型,只需要在类型的前面放置一个auto即可,减轻程序员的任务。

💓9. 基于范围的for循环

💞9.1 范围for的语法

在C++98中如果要遍历一个数组,可以按照以下方式进行:

void TestFor()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
		array[i] \*= 2;

	for (int\* p = array; p < array + sizeof(array) / sizeof(array[0]); ++p)
		cout << \*p << endl;
}

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中 引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量, 第二部分则表示被迭代的范围。

void TestFor()
{
	int array[] = { 1, 2, 3, 4, 5 };
    //下面的auto是元素的类型,我们也可以将其写为int,因为数组元素都是int类型
	for (auto& e : array)//必须使用引用才能拷贝,因为e只是array数组中元素的临时拷贝
		e \*= 2;

	for (auto e : array)


![img](https://img-blog.csdnimg.cn/img_convert/a2759002740eed48a330006d951ae9e2.png)
![img](https://img-blog.csdnimg.cn/img_convert/ce8daed4449360712df0ac872e4d2a17.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**

### 💞8.4 auto的意义


程序员不必再写出冗长的数据类型,只需要在类型的前面放置一个`auto`即可,减轻程序员的任务。


## 💓9. 基于范围的for循环


### 💞9.1 范围for的语法


在C++98中如果要遍历一个数组,可以按照以下方式进行:



void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
array[i] *= 2;

for (int\* p = array; p < array + sizeof(array) / sizeof(array[0]); ++p)
	cout << \*p << endl;

}


对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中 引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量, 第二部分则表示被迭代的范围。



void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
//下面的auto是元素的类型,我们也可以将其写为int,因为数组元素都是int类型
for (auto& e : array)//必须使用引用才能拷贝,因为e只是array数组中元素的临时拷贝
e *= 2;

for (auto e : array)

[外链图片转存中…(img-9won3AOL-1715667904805)]
[外链图片转存中…(img-cRD2S4jX-1715667904805)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值