【C++】C++入门第二课(函数重载 | 引用 | 内联函数 | auto关键字 | 指针空值nullptr)

目录

前言

函数重载

概念

重载函数的条件

C++支持重载函数的原理--名字修饰

引用

概念

特性

常引用(const引用)

使用场景

传值,传引用效率比较

引用和指针的区别

内联函数

概念

特性

auto关键字(C++11)

auto简介

auto的使用规则

指针空值nullptr(C++11)

C++98中的指针空值

结语


前言

这里是C++入门的第二课,主要还是补补C语言之前遗留下来的缺陷,在学习完本篇博客的内容之后,就可以进入激动人心的类和对象环节了。看过标题大家应该也知道要讲什么,话不多说,咱们开始今天的内容。

函数重载

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重
载了。比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!”

函数重载,简单来说就是允许定义同名函数,可以通过所传参数的数量和类型来判断运行哪一个函数,接下来咱们看具体定义。

概念

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这
些同名函数的形参列表(参数个数类型类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。

注:形参列表(参数 1.类型 2.个数或或 3.类型顺序)不同,都可以是重载的条件。

重载函数的条件

1.重载参数类型不同

#include<iostream>
using namespace std;
int Add(int left, int right)
{cout << "int Add(int left, int right)" << endl;return left + right;
}
double Add(double left, double right)
{cout << "double Add(double left, double right)" << endl;return left + right;
}int main()
{cout << Add(1, 2) << endl;cout << Add(1.1, 1.2) << endl;return 0;
}

代码的形参一份为整型,另一份为浮点型。当调用函数传入的是整型数据时,调用第一份声明形参为整型的代码;如果调用函数传入的是浮点型数据,则调用声明形参为浮点型的代码。 

2.参数个数不同

#include<iostream>
using namespace std;
void f()
{cout << "f()" << endl;
}
void f(int a)
{cout << "f(int a)" << endl;
}int main()
{f();f(3);return 0;
}

当调用函数不传入参数时,调用无参版的函数;当调用函数传入参数时,调用含参的重载函数。 

3.参数类型顺序不同

#include<iostream>
using namespace std;
void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}int main()
{f(1, 'm');f('m', 1);return 0;
}

运行时会自动匹配最合适的重载函数。 

满足上述三点条件中任意一点重载函数都定义在同一作用域内,就可以构成重载。 

 注:返回值不同不能构成重载,只能通过上述讲的参数不同进行重载。

如果返回值可以重载,会造成巨大的问题,程序无法从调用处区分最终函数运行结束后会产生什么类型的返回值,因此用返回值区分重载本身就是不可行不可靠的。

调用函数查找匹配的时候,编译器自动会匹配最符合的重载函数。

C++支持重载函数的原理--名字修饰

为什么C++支持函数重载,而C语言不支持函数重载呢?
在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接

C++支持函数重载的原理,很大程度上依赖于“名字修饰”(name Mangling)的过程。这种机制使得编译器能够区分同名但参数列表不同的函数。

名字修饰是编译器自动进行的一种处理过程,它将C++源码中的函数名和变量名转换成包含更多信息的唯一标识符。这些信息通常包括函数的参数类型,参数数量等,甚至可能包括所属的类名(对于类成员函数),通过这种方式,每个重载的函数都会被赋予一个独一无二的名字,确保在最后链接的时候能够区分出它们。

C++中允许函数重载,也就是允许一个作用域中存在多个同名函数,只要他们的参数列表不同,在编译成目标代码之后,所有的函数名都能通过修饰出的不同的名字而区分开来,确保了每个函数的调用都能显示的映射到正确的函数体上。名字修饰通过在函数名中编码函数类型等信息,实现了这一点。

名字修饰实例

下面有一组重载函数:

void Fun(int a, int b);
void Fun(double a, double b);

经过编译器的处理修饰,这些函数最后可能被处理为(不同编译器修饰规则不同,具体修饰结果取决于编译器)

  • Fun(int, int) 可能被修饰为 _23Funii_
  • Fun(double, double) 可能被修饰为 _23Fundd_

通过这种修饰方式,尽管这两个函数的名字相同,但在编译器的处理后它们获得了不同的名字,使得编译后的代码能够轻松识别出不同的重载函数。

名字修饰使得C++能够有效的支持重载和模板等功能,虽然这种机制对程序员来说是透明的,但理解其背后的原理对于深入掌握C++很有帮助。同时,这也是C++与C语言的一个重要区别:C语言不支持重载函数,大部分原因在于它没有采用类似的名字修饰机制。

我们来看看在Linux环境下用不同编译器编译相同代码对函数名的处理结果:

采用C语言编译器编译后的结果

在Linux下,采用gcc编译完成后,函数名字的修饰没有发生改变

采用C++编译器编译的结果

在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中
通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修
饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
到这里应该可以感受到,在C++中,编写代码方便的原因是大部分工作C++的编译器都帮你做掉了。这也使得匹配类型变慢,编译速度降低。但代码运行的是指令,这种匹配只会影响一部分编译速度,而不用担心会拖累代码运行的速度

引用

概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空
间,它和它引用的变量共用同一块内存空间。
比如:一个男孩,在家中被父母叫“儿子”,在学校里被叫“同学”。虽然称呼不同,但是最终的对象还是同一个人。引用就是一种给变量取别名的语法。

类型&  引用变量名(对象名) = 引用实体;

#include<iostream>
using namespace std;
int main()
{int a = 8;int& b = a;//定义引用类型cout << a << " " << b << endl;++a;cout << a << " " << b << endl;++b;cout << a << " " << b << endl;cout << &a << " " << &b << endl;return 0;
}

要注意的是,引用的类型必须和引用实体同种类型的。

特性

引用有几点特性:

  1. 引用在定义时必须要初始化
  2. 一个变量可以有多个引用
  3. 一旦引用一个实体,不能再引用其他实体(就跟变量不能重定义一样)
void TestRef()
{int a = 10;// int& ra; 这句语句在引用时未初始化,报错int& b = a;int& c = a;int& d = b;// int& d = a; 报错,重定义
}

常引用(const引用)

关于常引用,就是用const修饰的引用,只需要记住,在使用引用的时候,权限可以不变和缩小,但一定不能放大。这里的规则和指针极其相似。

void TestConstRef()
{const int a = 10;//int& ra = a; 该语句编译时会出错,a为常量const int& ra = a;// int& b = 10; 该语句编译时会出错,b为常量const int& b = 10;double d = 12.34;//int& rd = d; 该语句编译时会出错,类型不同const int& rd = d;//const引用支持不同类型
}

注:创建引用类型前加上const,可以在不同类型之间取别名,第三个案例中的rd里面的值为12。

使用场景

1.做参数

在用C语言中编写函数交换两个变量之间的值时,需要传指针才能实现,这时因为C语言函数传参是传值传递,传过去的只是原数据的拷贝,只有通过传址直接找到存储数据空间的地址,才能从函数内部影响到外部的数据。C++的引用成功的解决了此类问题,也就是常说的传引用。

#include<iostream>
using namespace std;void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}int main()
{int a = 5;int b = 8;cout << a << " " << b << endl;Swap(a, b);cout << a << " " << b << endl;return 0;
}

引用也是极大的减少了代码中指针的使用比例,也是补了C语言指针难用复杂的一个大坑。

2.做返回值

#include<iostream>
using namespace std;
int& Count()
{static int digit = 0;digit++;return digit;
}
int main()
{int& d = Count();cout << d << endl;Count();cout << d << endl;d++;cout << d << endl;return 0;
}

main函数中的变量d和函数内部的digit使用的空间是同一块,当里面digit++的时候外面d的值也会++,得益于Count函数的传引用返回static静态变量的创建(静态变量的生命周期存在于整个程序运行当中),这里传引用返回是可行的。

再来看这样一个案例,下面的代码中想想会输出什么结果?

#include<iostream>
using namespace std;
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;
}

c作为函数中的一个临时变量,在出了Add函数后会自动销毁,保存c数据的那部分空间此时就不存在了,这时候使用传引用返回,接收时就是一块未定义的空间,其性质就跟野指针一样

如果想更深入的理解此部分内容,可以看看我曾写过的一篇文章,里面细致讲解了函数栈帧的创建和销毁:
关于函数栈帧的创建和销毁-CSDN博客

注:函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用
引用返回,如果已经还给系统了,则必须使用传值返回

传值,传引用效率比较

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

下方TestFun1是传引用,TestFun2是传值:

下方TestFun1是传引用返回,TestFun2是传值返回:

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

这种效率差距在传递次数多,拷贝量大的情况下变得尤为明显。

引用和指针的区别

语法概念上引用就是一个别名,没有独立的空间,和其引用实体共用一块空间。
但其在底层上实际是有空间的,因为是按照指针的方式来实现的。

int main()
{int a = 10;int& ra = a;ra = 20;int* pa = &a;*pa = 20;return 0;
}

我们可以来看看上面这段代码的汇编:

会发现,引用和指针的汇编代码竟然一模一样!

引用和指针的不同点:

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

内联函数

概念

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

如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的
调用,其功能和C语言的宏相似。

在用inline修饰Add函数之后,代码就不会通过call调用函数,而是用函数体代码直接做添加。

特性

  1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会
    用函数体替换函数调用
    ,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运
    行效率。
  2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建
    议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、
    是递归、且频繁调用
    的函数采用inline修饰,否则编译器会忽略inline特性。《C++prime》第五版关于inline的建议:
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址
    了,链接就会找不到。

内联是一种用空间换取时间的方式,编译出来的可执行程序可能会变大:

举个例子,Swap函数如果有10行代码:

  • 如果不选择使用inline:则代码量为---> Swap + 调用(call) = 10 + 1000(call) 行指令。
  • 如果选择使用inline:则代码量为---> Swap * Swap指令数 = 10 * 1000 行指令。

故内联适合小函数,如果调用函数代码量大且调用次数多还选择使用内联,会导致代码量爆炸式增长。但是这个问题其实不用我们操心,编译器会自动选择是否将函数内联,你提供的inline对编译器来说只是一个建议,不起决定性作用。

内联函数其实是补C语言中宏的一个坑。由于宏的暴力替换,没有类型安全的检查,同时导致代码可读性差,可维护性差等原因,C++的祖师爷想到了用内联函数这样的方法去解决此问题。

auto关键字(C++11)

随着程序变得越来越复杂,程序中用到的类型也越来越复杂,经常会出现,类型难以拼写或含义不明确导致出错的情况。

#include <string>
#include <map>
int main()
{std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange","橙子" },{"pear","梨"} };std::map<std::string, std::string>::iterator it = m.begin();while (it != m.end()){//....}return 0;
}

在上面的这一段代码中,std::map<std::string, std::string>::iterator 就是一个类型,但是其类型太长,写起来非常麻烦且及其容易写错。虽然可以使用typedef取别名的方式,像这样:

typedef std::map<std::string, std::string> Map;

但是在实际中还是会遇到,typedef也解决不了的问题。

typedef char* pstring;
int main()
{//const pstring p1; 编译失败,p1底层为char* const p1而非const char* p1 const pstring* p2; // 编译成功,底层为char * const* p2return 0;
}

虽然第二条命令编译成功了,但p2的类型显然不是我们想要的。

在编程时,常常需要把表达式的值赋值给变量,这就要求在声明变量的时候清楚地知道表达式的
类型。然而有时候要做到这点并非那么容易,因此C++11给auto赋予了新的含义(之前版本auto有一个定义,但是基本没人用)。

auto简介

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

#include<iostream>
using namespace std;
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()是一个返回变量类型字符串的函数,我们可以借此观察 b c d 用auto声明过后的类型。

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

auto的使用规则

可以

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

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

2.在同一行定义多个变量

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

不可以

1.auto不能作为函数参数

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

3.为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法

指针空值nullptr(C++11)

C++98中的指针空值

在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现
不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下
方式对其进行初始化:

int* p1 = NULL;
int* p2 = 0;

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

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

可以看到,NULL可能被定义为字面常量0或者被定义为无类型指针(void*)的常量。不论采取何
种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,就比如:

程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的
初衷相悖。
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器
默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void
*)0。

所以在C++11中,就引入了nullptr指针空值,作为一个新关键字引入到C++体系之中。同时,为了提高代码的健壮性,后续使用指针空值时建议最好使用nullptr

结语

到这里,C++的入门部分总算是结束了。本篇博客讲到了C++相比于C新增的内容:函数重载,可以编写同名函数,但需要参数类型有区分度;讲到了引用,提供一种取别名的方式减少指针的使用,以及与传值相比的效率优越性;内联函数,用空间换时间,但是否内联取决于编译器本身;auto关键字,简化我们声明函数类型的过程,减少错误发生;指针空值nullptr,替换NULL提高程序的健壮性。

感谢大家的支持,博主后续会产出更多有意思的内容!♥

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/785691.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NLP技术大解析:人工智能应用从分词到情感分析的全面指南

自然语言处理&#xff0c;简称NLP&#xff0c;是人工智能领域中的一个重要分支&#xff0c;致力于让计算机理解和生成人类使用的自然语言。随着科技的飞速发展&#xff0c;NLP已经渗透到我们生活的方方面面&#xff0c;从智能语音助手到在线翻译工具&#xff0c;再到社交媒体的…

Vscode下使用markdown入门

1.安装vscode插件 1. **Markdown All in One** ——提供丰富的Markdown相关的快捷键、自动补全功能&#xff0c;提高md文档编写生产力 2. **Markdown Preview Ehanced** ——用于渲染当前编写文档的效果同步预览 3. **Paste Image** ——用于快速引用图片至Markdown文…

程序汪接的4万智慧餐饮项目

本文章来自程序汪背后的私活小团队&#xff0c;开发智慧餐厅的小程序 由于程序汪太忙于是把这个项目让一个靠谱粉丝开发了&#xff0c;当然开发质量和进度我会跟踪&#xff0c;具体分析如下 B站【我是程序汪】 老程序员接了一个4万的智慧餐饮项目&#xff0c;开发周期60天 小程…

YoloV8改进策略:BackBone改进|GCNet(独家原创)

摘要 非局部网络&#xff08;NLNet&#xff09;通过为每个查询位置聚合特定于查询的全局上下文&#xff0c;为捕获长距离依赖关系提供了一个开创性的方法。然而&#xff0c;经过严格的实证分析&#xff0c;我们发现非局部网络所建模的全局上下文在图像中的不同查询位置几乎相同…

EFCore 反向工程(DBFirst)----慎用

使用EFCore时一般推荐code first&#xff0c;也就是先创建实体类&#xff0c;然后根据实体类生成数据表。但是有时候数据表已经存在&#xff0c;这时候就需要基于数据库表来创建实体类。 首先已经有数据表&#xff0c;显示如下&#xff1a; 下载依赖包&#xff1a; Microsoft…

C++——哈希(一)

1. unordered系列关联式容器 在了解哈希之前我们先简单了解一下unordered系列的关联式容器&#xff0c;因为其底层就是用哈希来实现的&#xff0c;其实也没啥好说的&#xff0c;C11中&#xff0c;STL又提供了unordered系列的关联式容器(unordered_map和unordered_set)&#xf…

python练习二

# Demo85def pai_xu(ls_test):#创建一个列表排序函数命名为pai_xu# 对创建的函数进行注释"""这是一个关于列表正序/倒序排列的函数:param ls_test: 需要排序的列表:return:"""ls1 [int(ls_test[i]) for i in range(len(ls_test))]#对input输入的…

Demis Hassabis,这位被封为爵士的AI领域的杰出研究者和神经科学家,是否能成为Google的救星?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

一文教会女朋友学会日常Git使用!Git知识总结

文章目录 一文教会女朋友学会日常Git使用&#xff01;Git知识总结一、git基本知识了解1.git简介2.git区域了解3.git常用命令 二、常用工作场景1.克隆远程仓库&#xff0c;把仓库代码拉到本地2.推送代码到远程仓库&#xff08;1&#xff09;本地代码和远程仓库版本相同&#xff…

200个有趣的HTML前端游戏项目合集(持续更新中)

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

计算机组成原理1:计算机系统概述

此系列介绍计算机的组成原理&#xff0c;参考书&#xff1a;《计算机组成原理考研复习指导》(王道论坛组编)。 1.计算机发展史 1.1 计算机发展 计算机变化 第一代计算机 ( 1946 − 1957 ) (1946-1957) (1946−1957)&#xff1a;电子管时代。 逻辑元件采用电子管&#xff1b;使…

Java封装最佳实践:打造高内聚、低耦合的优雅代码~

​ 个人主页&#xff1a;秋风起&#xff0c;再归来~ 文章专栏&#xff1a;javaSE的修炼之路 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 1、封装 1.1 封装的概念 面向对象程序三大…

文献学习-24-用于少发罕见病诊断的动态特征拼接

Dynamic feature splicing for few-shot rare disease diagnosis Authors: Yuanyuan Chen, Xiaoqing Guo , Yongsheng Pan , Yong Xia , Yixuan Yuan Source: Medical Image Analysis 90 (2023) 102959 Keywords: 少样本学习 罕见病诊断 transformer 特征拼接 通道相似度 Ab…

FreeRTOS 任务挂起和恢复API函数

FreeRTOS 任务挂起和恢复API函数使用 挂起的作用就是当我们需要暂停某任务时候&#xff0c;等过一段时间在运行&#xff0c;这个时候要是使用删除和重建的方法就会当时任务进行时候的变量保存的值。当需要将这个任务停止运行一段时间的将这个任务挂起&#xff0c;当重新进行运…

华为云亮相KubeCon EU 2024,以持续开源创新开启智能时代

3月21日&#xff0c;在巴黎举办的云原生顶级峰会KubeCon EU 2024上 &#xff0c;华为云首席架构师顾炯炯在“Cloud Native x AI&#xff1a;以持续开源创新开启智能时代”的主题演讲中指出&#xff0c;云原生和AI技术的融合&#xff0c;是推动产业深刻变革的关键所在。华为云将…

进度管理与成本管理

1.裁剪考虑因素 2. 定义计划是把WBS分解的活动在分解成更小的活动。 3. 4.资源平衡会改变关键路径 5.资源平滑只能在自由和浮动时间延迟 6. 7. 8.成本管理&#xff0c;论文要写不足与解决过程 9.成本的类型 10. 11.规划XX管理的时候&#xff0c;输入一般有章程和项目…

C语言动态内存讲解+通讯录2.0

文章目录 前文malloc和freecallocrealloc枚举常量的简单说明及使用 通讯录2.0动态开辟通讯录,满了就扩容保存数据和载入数据 通讯录2.0演示推荐好用的软件 前文 本文主要介绍动态开辟的几个函数,以及改进之前的通讯录。 我们局部变量等是在栈区上开辟空间的,而我们动态开辟的空…

新model开发记录

模型使用 -- 用blender导出为 fbx &#xff0c;修改渲染方式&#xff08;点击模型->Materials->Extract Materials(将材质从fbx中 单独提取出来了)->Materials 选择 Shader -> SimpleURPToonLitExample 点开脸的材质&#xff0c;勾选第一条&#xff09; 解决角色…

力扣-python-故障键盘

题解&#xff1a; from collections import dequeclass Solution:def finalString(self, s: str) -> str:# 创建一个双端队列用于存储字符q deque()# 定义一个标志位&#xff0c;用于标记当前字符应该添加到队列的哪一端head False# 遍历输入的字符串s的每一个字符for ch…

C++刷题篇——05静态扫描

一、题目 二、解题思路 注意&#xff1a;注意理解题目&#xff0c;缓存的前提是先扫描一次 1、使用两个map&#xff0c;两个map的key相同&#xff0c;map1&#xff1a;key为文件标识&#xff0c;value为文件出现的次数&#xff1b;map2&#xff1a;key为文件标识&#xff0c;va…