C++入门

在这里插入图片描述

文章目录

  • 😀1. 命名空间
    • 😄1.1 命名空间定义
    • 😄1.2 命名空间使用
  • 😊2. 输入和输出
  • 😉3. 缺省参数
    • 🫠3.1 缺省参数概念
    • 🫠3.2 缺省参数分类
  • 😬4. 函数重载
    • 🙄4.1 函数重载概念
    • 🙄4.2 函数重载原理
  • 😮5. 引用
    • 😯5.1 引用概念
    • 😯5.2 引用特点
    • 😯5.3 使用场景
    • 😯5.4 常引用
    • 😯5.5 引用和指针区别
  • 🫥6. 内联函数
    • 😶‍🌫️6.1 概念
    • 😶‍🌫️6.2 特性
  • 🤗7. 语法糖
    • 🤭7.1 auto关键字
      • 🫡auto简介
      • 🫡auto使用细则
    • 🤭7.2 基于范围的for循环
      • 🫡范围for的语法
      • 🫡范围for的使用条件
    • 🤭7.3 nullptr

😀1. 命名空间

在写C的代码时,会用到大量的变量,如果工程量一大,就有可能发生变量名冲突或者是使用某个变量名时,名字和库里面的一样,这样就会导致访问冲突。当代码全部总和的时候,改变量名就是一个头疼的问题,这里变量冲突了,那里变量冲突了,十分头疼。

image-20230523223453863

于是在C++里面就引入了命名空间namespace,来解决这种命名冲突问题。

😄1.1 命名空间定义

C语言中,{}里面的叫做,在同一个域里面,变量不能重复定义。

image-20230523223308556

​ 而在C++里面,定义命名空间,需要使用namespace,后面跟空间的名字,然后接一对{}即可,{}中即为命名空间的成员。

namespace Test
{
	//定义变量
	int rand = 10;
	
	//定义函数
	int Add(int a, int b)
	{
		return a + b;
	}

	//定义类型
	struct Node
	{
		struct Node* next;
		int val;
	};

	//嵌套定义
	namespace T1
	{
		int Sub(int a, int b)
		{
			return a - b;
		}
	}
}

😄1.2 命名空间使用

如果全局域和局部域的变量名一样,但是又想使用全局域这个变量该怎么办呢?

::是C++里面的作用域限定符,::的左边用于指定所属的命名空间或者类,如果左边是空白的,则代表访问全局域。

image-20230523225934276

命名空间访问的方式有三种:

  1. 命名空间+域作用限定符

    namespace T
    {
    	int a = 10;
    }
    
    int main()
    {
    	//命名空间+域作用限定符
    	printf("%d\n", T::a);
    	return 0;
    }
    
    
  2. 空间某个成员引入

    namespace T
    {
    	int a = 10;
    	int b = 20;
    }
    
    //空间域部分展开
    //可理解为 将变量b暴露在全局域中
    using T::b;
    int main()
    {
    	//error a未展开,不可直接使用
    	//printf("%d\n", a); 
    
    	printf("%d\n", b); //20
    	return 0;
    }
    
  3. 空间域全部展开

    namespace T
    {
    	int a = 10;
    	int b = 20;
    
    	int Add(int a, int b)
    	{
    		return a + b;
    	}
    }
    
    //展开命名空间域
    using namespace T;
    
    int main()
    {
    	printf("%d\n", a);
    	printf("%d\n",T::b);
    	printf("%d\n",Add(5, 23));
    }
    
    

看过C++的一些代码,经常会看到这样的代码:

#include<iostream>
using namespace std;

C++的标准库中的大部分内容都定义在std命名空间中,直接展开的好处就是书写比较方便;但是对于初学者来说,最好是不要全部展开,因为我们定义变量时,不知道这个名称是不是标准库里面的名称,会不会导致冲突,所以刚开始学习时,如果要用,前面加上std::,明确指定使用的命名空间即可。

另外,C++的头文件现在都不加.h后缀。在早期为了兼容C语言,保持了C的命名约定,即以.h为后缀。但在引入标准库时,为了和C语言头文件区分,规定C++头文件不带.h

😊2. 输入和输出

大家都知道,咱们是特别有礼貌的,入门第一步一定是先打个招呼“Hello World”,那C++如何“打招呼”呢?

iostream头文件定义了两个重要的输入输出流对象:cincout

  1. cincin是C++标准库中的输入流对象,用于从输入设备(如键盘)读取数据。通过cin,可以接收用户的输入,并将输入数据存储到相应的变量中。
  2. coutcout是C++标准库中的输出流对象,用于向输出设备(如控制台)输出数据。通过cout,可以将数据、文本或变量的值输出到控制台或其他输出流中。
#include<iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
    int a = 10;
	int number;
	cout << "Hello World" << endl; //endl 是换行符
    cout << a << endl;
	cin >> number;
	cout << "number = " << number << endl;
	return 0;
}
  • 其中<<在C语言表示的是移位操作符,但是在cout << "Hello World" << endl;表示流插入运算符,在输出操作中,<< 运算符将数据从右侧操作数插入到左侧操作数所代表的输出流中。

    >>同理,表示流提取运算符,在输入操作中,>> 运算符从左侧操作数所代表的输入流中提取数据,并将其存储到右侧操作数所代表的变量中。

  • cout相比printfcout可以连续输出,而且会自动识别类型;cinscanf同理(这些只是以目前的知识简单分析)。

  • printfscanf的速度会比coutcin要快,因为C++的IO流要兼容C语言,每次读的时候,都会检查是否有C语言的东西,所以在一定程度上会影响性能。

😉3. 缺省参数

🫠3.1 缺省参数概念

C语言里面调用函数时,有时候我们可能不知道要传多少参数,当时我们采用的是用一个,来设置默认值,但是这样就会导致,如果需要传参的时候,不能进行传参,不够灵活。

于是C++里面就引入了缺省参数这个概念:函数或方法定义中指定的具有默认值的参数。它们允许在调用函数时省略对应的参数,而函数将使用预先定义的默认值来代替。

这就好比吃饺子,不晓得吃多少合适,那就默认吃7个,不多也不少。

如果知道自己的量,比如说我能吃14个,那就直接上14个饺子,蘸点醋,吃完该上班上班,该上学上学。

void eatDumplings(int defaultE = 7)
{
	cout << defaultE << endl;
}

int main()
{
	eatDumplings();  //不知道吃几个
	eatDumplings(14);//吃14个
	return 0;
}

🫠3.2 缺省参数分类

  • 全缺省

    void Func(int a = 1, int b = 2, int c = 3) //每个参数都设置缺省值
    {
    	cout << "a = " << a << endl;
    	cout << "b = " << b << endl;
    	cout << "c = " << c << endl;
    }
    
    int main()
    {
    	Func();
    	return 0;
    }
    
  • 半缺省

    void Func(int a, int b = 2, int c = 3) //a 需要给具体参数
    {
    	cout << "a = " << a << endl;
    	cout << "b = " << b << endl;
    	cout << "c = " << c << endl;
    }
    
    int main()
    {
    	Func(1);
    	return 0;
    }
    

    Tips:

    1. 设置半缺省参数时,必须从右往左,依次给出来,不能跳着给;传参时,只能从左往右,不能跳着传参。

    image-20230525214832843

    1. 缺省参数不能在函数声明和定义中同时出现。

      这就好比,一山不容二虎,声明说默认为1,定义说默认为2,这该听谁的?

      如果声明和定义分开的时候,在声明时就应该设置缺省参数,不能到定义的时候再来设置。因为程序如果要调用该函数,是先找到声明,有这个声明,再去查看定义。

      GIF 2023-5-25 21-59-48

😬4. 函数重载

🙄4.1 函数重载概念

中华文化博大精深,一句话可能有多个意思,例如:A心高气傲,“谁也看不上”,B的debuff叠满“谁也看不上”。这就是重载

而C++里的函数重载,大概意思也是如此:在同一个作用域内,可以定义多个具有相同名称但参数列表不同的函数。函数重载允许使用相同的函数名执行不同的操作,具体取决于函数调用时提供的参数。

函数重载的特点如下:

  1. 函数名称相同;
  2. 参数列表不同(参数类型、参数顺序、参数个数);
  3. 返回类型不同不足以重载函数
int Add(int a, int b) //参数列表: (int a, int b)
{
	return a + b;
}

double Add(double a, double b) //参数列表: (double a, double b)
{
	return a + b;
}

int Add(int a, int b, int c) //参数列表: (int a, int b, int c)
{
	return a + b + c;
}

🙄4.2 函数重载原理

为什么C语言不支持这个重载,而C++可以支持呢?

C程序要执行的话,分为四个阶段:

  1. 预处理:对源代码文件进行宏展开、条件编译等操作,生成一个经过预处理的新文件(通常以.i.ii为扩展名)。
  2. 编译:检查语法,生成汇编代码。
  3. 汇编:将汇编代码转换成二进制机器码。
  4. 链接:将目标文件和可能的库文件合并在一起,解析符号引用,处理重定位信息,并生成最终的可执行文件。

在编译的时候,C语言编译器是直接调用的函数地址(Linux环境演示)

image-20230526012913188

而C++编译器,会将函数的参数类型带进来

image-20230526013231213

这就叫函数名修饰规则

了解了这些,我们就能了解,为什么返回类型不一样不构成函数重载,因为返回类型并没有参与这个规则。

如果对编译链接这块有疑惑,可查看此篇文章:被隐藏的过程

😮5. 引用

😯5.1 引用概念

在C语言中,我们可以通过指针间接的访问和修改指向的对象,这个指针相当于中间商,中间商肯定是要赚点“差价”的,这个“差价”就是指针也需要占用内存空间。

image-20230526015735948

还记得刚学指针的时候,对于这些概念,痛苦不堪。可能祖师爷也感觉这样麻烦,不如干脆一点,直接一对一,不着中间商了。

于是引入了引用的概念:提供了一个变量或对象的别名,可以通过引用直接访问和操作该变量或对象。

这就好像给人家取外号一样,“小甜甜”、“牛夫人”都是铁扇公主,只是叫法不一样而已。

😯5.2 引用特点

  1. 初始化: 引用在定义时必须进行初始化,并且一旦初始化完成后,它将一直引用同一个对象,无法重新指向其他对象。
  2. 无地址: 引用本身不占用内存空间,它只是作为已存在对象的别名,因此没有自己的地址。
  3. 专一: 引用只能有一个实体,而一个实体可以有多个引用。
void TestRef()
{
	int a = 0;
    int A = 1;
    int& B = a;
	int& b = a;
	int& c = b;
	//int& d;  error
}

Tips:

引用类型必须和实体是同种类型

GIF 2023-5-26 2-22-34

😯5.3 使用场景

  1. 做参数

    void Swap(int& a, int& b) //传引用过去
    {
    	int tmp = a;
    	a = b;
    	b = tmp;
    }
    
    int main()
    {
    	int a = 1;
    	int b = 2;
    	cout << "a = " << a << endl;
    	cout << "b = " << b << endl;
    	Swap(a, b);
    	cout << "a = " << a << endl;
    	cout << "b = " << b << endl;
    	return 0;
    }
    
  2. 做返回值

    int& func()
    {
    	static int n = 1; //静态变量
    	return n;
    }
    
    int main()
    {
    	int ret = func();
    	cout << ret << endl;
    	return 0;
    }
    

    下面这段代码和上面的有什么区别呢?

    int& func()
    {
    	int n = 1;
    	return n;
    }
    
    int main()
    {
    	int& ret = func();
    	cout << ret << endl;
    	cout << " " << endl;
    	cout << ret << endl;
    	return 0;
    }
    //输出结果:
    // 1
    // 随机值
    

    第一段代码的n静态变量,静态变量是存放到静态区中,函数栈帧的销毁,这个变量依然存在,不影响使用。

    而第二段代码的n是普通变量,该函数使用完毕之后,栈帧销毁,这个变量也随之销毁。我们第一次输出是正常结果,不同编译器会做出不同的处理,博主这里的用的是VS2022,该编译器函数空间被释放之后,并没有进行刷新;当我们在调用依次输出函数时,这时就会重新压栈,替代之前的func所在的空间,所以第二次会显示随机值。

    Tips:

    函数运行结束之后,我们所说的“销毁”,并不是该空间不存在了,而是说对应的空间被系统回收。就好比去图书馆借书,我们阅读完毕之后还是要还给图书馆,但是这本书,本身还是存在的。

不管是做参数还是做返回值,在一定程度上可以提高大型对象的传递效率。

但是返回引用时要确保被引用的对象仍然有效,否则会引发未定义行为。因此,在返回引用时需要谨慎处理,确保被引用的对象在函数生命周期内保持有效。

😯5.4 常引用

int main()
{
	//× 引用过程中,权限不能放大
	const int a = 1;
	//int& b = a;  //error

	//√ c拷贝给d,权限没有放大,d的改变不影响c
	const int c = 1;
	int d = c;

	//√ 引用过程中,权限可平移或者缩小
	int n = 0;
	const int& m = n;
    
    //隐式类型转换,会产生临时变量。临时变量具有常性
	double dd = 1.11;
	int ii = dd;  
	//int& rii = dd;  //error
	const int& dii = dd;
	return 0;
}

😯5.5 引用和指针区别

语法层面,引用就相当于一个“外号”,没有独立的空间。但在底层逻辑上,是有空间的,引用的底层还是用指针来实现的。

int main()
{
	int a = 0;
	//引用 不开空间
	int& ra = a;
	ra = 10;

	//指针 开空间
	int* pa = &a;
	*pa = 20;
	return 0;
}

汇编指令:

image-20230527190832995

我们发现引用的底层和指针的底层是一样的。这是因为编译器可以将引用转换为指针来进行处理,引用在 C++ 中通常被编译器实现为指针的语法糖,这种转换可以在不改变代码行为的前提下提供更高效的实现。

我们现在看虽然在汇编上一样,但在更复杂的程序中或涉及更多操作时,它们的汇编代码可能会有所区别,这具体由编译器来进行转换。要理解的是指针引用,是两种不同的概念,它们是存在一定区别的:

  1. 引用是一个别名,用于给已经存在的对象起另一个名称;

    指针是一个变量,用于存储另一个对象的地址。

  2. 引用必须始终引用一个有效的对象,它不能为 null;

    指针可以具有空值(null),表示它没有指向任何有效的对象。

  3. 引用一旦绑定到一个对象后,不能再重新绑定到其他对象;

    指针可以在任何时候重新赋值,将指向不同的对象。

  4. 引用不占用额外的空间,它只是已经存在的对象的别名;

    指针需要额外的空间来存储另一个对象的地址,并且需要手动管理内存,包括内存的分配和释放。

总体而言,引用提供了一种更加安全和方便的访问对象的方式,它不需要显式的解引用操作,并且可以避免空指针问题指针则提供了更大的灵活性和底层控制能力。选择使用引用还是指针,取决于具体的需求和场景。

🫥6. 内联函数

😶‍🌫️6.1 概念

在写代码的时候,可能会遇到需要频繁调用一个函数,函数调用过程中,涉及到了栈帧的创建和销毁,以及相关的参数传递返回地址保存等操作。这些操作会带来一定的开销。在C语言中,如果函数比较简单,那我们就可以用,来替代,这就避免了频繁创建销毁栈帧的过程:

int Add(int a, int b)
{
	return a + b;
}

//宏替代
#define ADD(x,y) ((x)+(y)) 

int main()
{
	for (int i = 0; i < 10000; i++)
	{
		cout << Add(i, i + 1) << endl;
		cout << ADD(i, i + 1) << endl;
	}
	return 0;
}

但是这样的话,也存在一些潜在问题,无法调试检查,可维护性也较差,而且宏是直接展开,哪里是整体还需要加上括号,这样也不好控制。

于是C++中引入了内联函数的概念:一种在编译器编译阶段进行的优化手段,用于将函数调用处的代码替换为函数体的内容,从而避免了函数调用的开销。内联函数在C++中通过关键字 inline 来声明。

inline int Add(int a, int b)
{
	return a + b;
}

//#define ADD(x,y) ((x)+(y)) 
int main()
{
	cout << Add(1, 2) << endl;
	return 0;
}

我们查看反汇编可以观察到区别:

image-20230528204850554

Tips:

debug模式下因为要调试,所以内联并不会展开,需要对编译器进行设置(以VS2022为例):

image-20230528205056999

😶‍🌫️6.2 特性

  1. inline是一种以空间换时间的做法,因为inline会将函数体的代码直接展开到调用点,这可能导致代码量的增加。如果内联函数的函数体较大,会导致代码膨胀,增加了代码的存储和加载开销。

  2. inline对于编译器而言,只是一个建议,意思就是内联只是向编译器发出一个请求,编译器可以选择忽略这个请求,不同的编译器对于inline的实现机制可能不同。

    这里的代码如果直接展开的话,相比正常来说效率是更低的,所以编译器忽略了此次请求。

    image-20230528210723300

  3. inline的声明和定义通常放在头文件中,不建议将其分离。因为inline是直接展开,没有函数地址,就会导致链接不上。

    image-20230528211506780

🤗7. 语法糖

平时我们写代码就很难受了,要是写的代码又臭又长就更加难受了。于是在C++中,就添加了一些语法糖,简化了一些语法结构,减少代码的冗余,使代码简洁、易读。这样就让我们能够“苦中作乐”了。

🤭7.1 auto关键字

🫡auto简介

C语言中,有typedef可以给类型取别名,但是typedef当过多的类型别名存在时,阅读代码变得更加困难,因为读者必须去查找别名的定义以了解其实际类型。

早期的C++标准中,auto关键字具有不同的含义,它被用于声明具有自动存储期的局部变量。然而,由于其模糊性和潜在的歧义,很少有人在实际编程中使用。

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

int TestAuto()
{
	return 10;
}

int main()
{
	int a = 1;
	auto b = &a;
	auto c = 1.11;
	auto d = 'x';
	auto e = "Hello";
	auto f = TestAuto();
	
	//输出类型
	cout << typeid(a).name() << endl; //推断类型:int
	cout << typeid(b).name() << endl; //推断类型:int*
	cout << typeid(c).name() << endl; //推断类型:double
	cout << typeid(d).name() << endl; //推断类型:char
	cout << typeid(e).name() << endl; //推断类型:char const *
	cout << typeid(f).name() << endl; //推断类型:int

	//使用auto定义变量必须初始化
	//auto n; //error
	return 0;
}

🫡auto使用细则

  1. 初始化

    auto关键字的类型推断是基于变量的初始化表达式。因此,确保变量的初始化表达式提供足够的信息,以便编译器可以准确推断出变量的类型。

  2. auto与指针和引用结合

    int main()
    {
    	int x = 10;
    	auto a = &x;
    	auto* b = &x;
    	auto& c = x;
    	
    	cout << typeid(a).name() << endl; //int*
    	cout << typeid(b).name() << endl; //int*
    	cout << typeid(c).name() << endl; //int
    	return 0;
    }
    

    Tips:

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

    当使用auto关键字推断引用类型时,需要注意引用的生命周期和可变性。

  3. 同一行定义多个变量

    int main()
    {
    	//√ 类型相同
    	auto a = 1, b = 2;
    
    	//× 类型不同
    	//auto c = 1, d = 1.1; //error
    	return 0;
    }
    

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

  4. auto不可推导的场景

    • auto不能作为函数的参数

      void TestAuto1() //无返回类型
      {
      	;
      }
      
      void TestAuto2(auto x) //此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
      {
      	;
      }
      
    • auto不能声明数组

      void TestAuto()
      {
      	auto arr[] = { 1,2,3 }; //error
      }
      

🤭7.2 基于范围的for循环

🫡范围for的语法

在C语言中,我们变量数组通常采用以下方式:

int main()
{
	int arr[] = { 1,2,3,4,5 };
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d\n", arr[i]);
	}
	return 0;
}

对于一个有范围的集合而言,由我们来说明循环的范围是多余的,有时候还会容易犯错误。

因此C++11中引入了基于范围的for循环。

void TestFor()
{
    int array[] = { 1, 2, 3, 4, 5 };
    //分为两部分:第一部分是范围内用于迭代的变量,第二部分表示被迭代的范围。
    for (auto& e : array)
        e *= 2;
    
    for (auto e : array)
        cout << e << " ";
}

Tips:

与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。

🫡范围for的使用条件

  1. for循环迭代的范围必须是确定的;
  2. 迭代的对象要实现++==的操作。

🤭7.3 nullptr

#ifndef NULL
#ifdef __cplusplus //判断当前环境是否为C++编译环境
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

我们发现,在关于NULL其实是一个宏定义,在C++环境中被定义为0,这就就会影响我们使用空指针的时候,可能会出现一些与我们意向相悖的结果:

void f(int)
{
	cout << "f(int)" << endl;
}
void f(int*)
{
	cout << "f(int*)" << endl;
}
int main()
{
	f(1); // f(int)
	f(NULL); // f(int)
	f((int*)NULL); // f(int*)
	return 0;
}

因为要兼容C语言,所以在C和C++代码中都可以使用NULL来表示空指针。

但这样就对于C++比较难受了,于是在C++11中,引入了nullptr关键字,用来表示空指针。

Tips:

  1. 因为nullptr是C++11中引入的关键字,所以不需要包含头文件,C++程序中直接使用就行
  2. 在C++11中,sizeof(nullptr)sizeof((void*)0)所占的字节数相同
  3. 对于C++的代码,建议使用nullptr以获得更好的类型安全性和可读性。此外,C++标准库中的新功能和API也更倾向于使用nullptr

当然了,这些只是一部分,C++很苦,所以祖师爷在设计的时候,在许多地方放了甜甜的“糖”,这得在之后学习的过程中,我们慢慢摸索。

本篇文章讲的其实都是一些C++关于C的一些补充或者优化,C++在继承了C语言的基础上,引入了更多的特性和概念。

那么本次的分享就到这里,如果有用的话,希望三连支持一下,我们下期再见,如果还有下期的话。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TypeScript9-声明文件

本篇文章来讲 TypeScript 的声明文件。 当我们在使用第三方库的时候&#xff0c;很多第三方库不是用 TS 写的&#xff0c;它们是通过原生的 JavaScript 或者是浏览器 / 或者是 node 提供的 run time 对象。如果我们直接使用 TS 肯定就会报编译不通过。 1. 声明语句 假设一个…

浅析变电站无人值守管理的模式与特点

安科瑞虞佳豪 近年来&#xff0c;随着电网的发展&#xff0c;变电站实行无人值班管理模式已成为电网的发展方向。自1998年始&#xff0c;辉县市就开始了变电站综合自动化改造&#xff0c;截止目前全局所属24座变电站&#xff08;其中35kV19座、110kV5座&#xff09;已全部实现…

API自动化测试【postman生成报告】

PostMan生成测试报告有两种&#xff1a; 1、控制台的模式 2、HTML的测试报告 使用到一个工具newman Node.js是前端的一个组件&#xff0c;主要可以使用它来开发异步的程序。 一、控制台的模式 1、安装node.js 双击node.js进行安装&#xff0c;安装成功后在控制台输入node …

Java集合基础

4 集合基础 集合提供一种存储空间可变的存储模型,存储的数据容量可以改变ArrayLis<>: 可调整大小的数组实现<>:是一种特殊的数据类型,泛型可储存重复元素怎么使用呢 在出现E的地方我们使用引用数据类型替换即可举例:ArrayList<String>、ArrayList<Stu…

财务共享时代企业数智化应用能帮我们做些什么?

随着企业规模的不断扩大和业务范围的逐步扩展&#xff0c;财务工作的难度和复杂度也在不断提高&#xff0c;传统的手工录入和处理方式呈现出流程长、效率低、易出错等问题。为了提升财务工作的效率和准确性&#xff0c;越来越多的企业开始利用数智化应用打造企业内部的财务数智…

绝对不能错过的7个零基础免费的ChatGPT镜像网站

还在为打不开openai官网烦心&#xff1f;本文帮你实现ChatGPTMidJourney自由(&#xffe3;∇&#xffe3;)/ &#x1f4d2;收集了一些截至目前(2023年5月25日午12:00)可以免费访问&#xff0c;并且零基础也能正常使用的镜像网站&#xff0c;后续将持续维护更新(&#xff61;&a…

平安银行广州分行立足地域文化,增强差异化权益服务软实力

立足地域文化&#xff0c;拓展差异化权益服务 瓦屋纸窗之下&#xff0c;一盏清茶&#xff0c;三五好友&#xff0c;怡然自若。中国人对茶的喜爱由来已久&#xff0c;茶文化已成为中华传统文化中一张亮丽的名片&#xff0c;而广东茶文化则是中国四大茶文化系列之一。平安银行广州…

抖音seo优化源代码搭建+抖音小程序私有化开源部署

抖音seo优化源码&#xff0c;抖音seo矩阵系统搭建&#xff0c;抖音账号矩阵系统开发&#xff0c;企业在做账号矩阵过程中&#xff0c;最头疼的莫过于私域线索转化&#xff0c;作为开发者都知道&#xff0c;目前市面上我们了解的矩阵系统除了挂载POI信息外&#xff0c;无法挂载留…

unity四叉树和视锥体剔除

这个最好还是看代码&#xff0c;项目有注释放在这里&#xff1a; GetbadEarlyup/Quadtree-cone-scene: 这是一个unity四叉树场景视锥体剔除的Demo (github.com)https://github.com/GetbadEarlyup/Quadtree-cone-scene国内地址&#xff1a; Quadtree-cone-scene: unity四叉树和…

VESD静电监控系统:提高静电防护效果与管理效率

随着科学技术不断发展&#xff0c;现代的工业对静电防护的要求越来越高。因为静电的存在可能会对产品质量、工作环境、甚至是人身产生威胁。静电监控系统是一项高效的管理工具&#xff0c;能够有效地控制和监测静电产生的情况&#xff0c;提高静电防护效果和管理效率。 VESD静电…

U盘超级加密3000试用版与正式版的区别有哪些?

U盘超级加密3000是一款专业的U盘加密软件&#xff0c;它可以为U盘、移动硬盘、内存卡等移动存储设备加密。软件拥有正式版和试用版&#xff0c;那么这两个版本有什么区别呢&#xff1f;下面我们就一起来了解一下。 U盘超级加密3000试用版和正式版的区别 打开软件时的区别 试用…

基于SSM的酒店客房管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 酒店管理系统是一款高…

VMware重新安装VMwareTool字体为灰色情况+ubuntu时间设置

文章目录 前言&#xff1a;1. 重新安装VMwareTool字体为灰色2. VMware下ubuntu的时间设置 前言&#xff1a; 之前退出VMware关闭的时候没有等待虚拟机的状态保存&#xff0c;强制关机了。这就导致后面使用的时候&#xff0c;共享目录无法显示情况。对于上面的情况我的博客里面…

ASP-IIS中间件文件解析与写权限

ASP-IIS中间件文件解析与写权限 IIS文件解析 IIS 6 解析漏洞 1、该版本默认会将*.asp;.jpg 此种格式的文件名&#xff0c;当成Asp解析 2、该版本默认会将*.asp/目录下的所有文件当成Asp解析。 如&#xff1a;logo.asp;.jpg xx.asp/logo.jpgIIS 7.x 解析漏洞 在一个文件路…

SSM编程---Day 02

目录 一、核心配置文件 二、junit介绍 三、自定义java注解 四、自定义注解 五、添加log4j的支持 六、sql映射文件的介绍 一、核心配置文件 1、核心配置文件中需要注意顺序 2、根节点 <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN"…

打家劫舍 III——力扣337

文章目录 题目描述法一&#xff1a;动态规划 题目描述 法一&#xff1a;动态规划 问题简化&#xff1a;一棵二叉树&#xff0c;树上的每个点都有对应的权值&#xff0c;每个点有两种状态&#xff08;选中和不选中&#xff09;&#xff0c;问在不能同时选中有父子关系的点的情况…

js正则校验特殊的不可见字符

背景 表单的输入框&#xff0c;用户可能从Excel或者其他地方直接复制粘贴&#xff0c;这时候提交到后端会导致获取的用户输入中包含一些特殊的不可见字符&#xff0c;比如tab键或者制表符等&#xff0c;这时需要在前端对用户输入做一些检验&#xff0c;检查是否存在不可见字符…

【PHP】问题已解决:宝塔面板搭建php网站无法上传图片或是文件(保姆级图文)

目录 问题情况原因和解决方法总结 『PHP』分享PHP环境配置到项目实战个人学习笔记。 欢迎关注 『PHP』 系列&#xff0c;持续更新中 欢迎关注 『PHP』 系列&#xff0c;持续更新中 问题情况 宝塔面板搭建php网站无法上传图片或是文件。 原因和解决方法 检查你的php里是否安装…

任务19 简单个人电话号码查询系统

系列文章 任务19 简单个人电话号码查询系统 问题描述 人们在日常生活中经常需要查找某个人或某个单位的电话号码&#xff0c;本实验将实现一个简单的个人电话号码查询系统&#xff0c;根据用户输入的信息&#xff08;例如姓名等&#xff09;进行快速查询。基本要求 (1) 在外存…

k8s 对已完成job自动清理

job在处理完一个任务以后&#xff0c;状态会变成Completed&#xff0c;job在状态为Completed的时候默认不会自动清理的&#xff0c;还会继续占用系统资源。 TTL-after-finished控制器 kubernetes中有专门的控制器可以自动清理已完成的job,就是TTL-after-finished控制器。 TTL…