【C++】C++入门必备知识详细讲解

C++入门必备知识

  • 一、命名空间
    • 1. namespace
    • 2. namespace 的使用场景
  • 二、了解 C++ 中的输入和输出
  • 三、缺省参数
  • 四、函数重载
    • 1. 函数重载的概念
    • 2. C++支持函数重载的原理
  • 五、引用
    • 1. 引用的概念
    • 2. 引用特性
    • 3. 常引用
    • 4. 引用的使用场景
      • (1)做参数(传引用传参)
      • (2)做返回值(传引用返回)
      • (3)引用和指针的区别
  • 六、内联函数
    • 1. #define定义宏
    • 2. 内联函数的概念
    • 2. 内联函数的特性
  • 七、auto关键字
  • 八、基于范围的for循环(C++11)
  • 九、指针空值 nullptr

首先我们先要知道,C++是在C的基础之上,容纳进去了面向对象编程思想,并增加了许多有用的库。本章将会带大家了解,C++是补充C语言语法的不足,以及C++是如何对C语言设计不合理的地方进行优化的。

一、命名空间

1. namespace

在C/C++中,变量、函数等等都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突,namespace 关键字的出现就是针对这种问题的。

例如,我们想定义一个变量 sqrt ,直接定义在全局变量然后编译是可以通过的,例如下图:

在这里插入图片描述
但是,我们知道 sqrt 其实是一个库函数,它包含在 math.h 的头文件中,假设我们加上 math.h 的头文件,还能编译过吗?答案是不能,因为它们重名了,如果包含了 math.h 的头文件,编译不会通过,会报下图中的错误:
在这里插入图片描述

那么有没有好的解决方案呢,答案是有的,C++中就增加了 namespace 这样的关键字解决这样的问题。例如我们可以将我们需要定义的变量放入 namespace 的命名空间中,然后在使用让编译器在指定的命名空间中寻找;如果不指定编译器,编译器优先会在全局域中寻找变量;namespace 的使用:

		#include <stdio.h>
		#include <math.h>
		
		// 命名空间的名字
		namespace Young
		{
			int sqrt = 10;
		}
		
		int main()
		{
			printf("%d\n", Young::sqrt);
			return 0;
		}

上述代码的使用就是让编译器在指定的命名空间 Young 中去寻找变量 sqrt 然后使用这个变量,这样就不会与库函数中的 sqrt 函数有命名冲突了;Young 是一个可以自己命名的命名空间的名字,可以取任意名字,不一定是 Young.

printf("%d\n", Young::sqrt);中,sqrt 前面的 :: 符号,叫做域作用限定符,意思是让编译器使用域作用限定符前面的命名空间中定义的东西。

2. namespace 的使用场景

除了上面我们使用 namespace 在命名空间中定义变量外,还可以定义函数、结构体等;除此之外,还可以嵌套使用。例如以下代码:

		namespace Young
		{
			//变量
			int sqrt = 10;
		
			// 函数
			int Add(int a, int b)
			{
				return a + b;
			}
		
			// 结构体
			struct ListNode
			{
				int data;
				struct ListNode* next;
			};
		
			// 嵌套使用 
			namespace Y
			{
				int a = 10;
			}
		
		}
		
		int main()
		{
			int ret = Young::Add(1, 2);
			printf("%d\n", ret);
		
			struct Young::ListNode node;
		
			printf("%d\n", Young::Y::a);
		
			return 0;
		}

上述代码中主函数部分,结构体中的域作用限定符是要在 ListNode 前使用,而不是在 struct 前使用;嵌套使用 namespace 是从右往左看,到指定的命名空间中去寻找;

虽然这种方法可以有效避免命名冲突问题,但是每次用的时候都要在前面加上域作用限定符,是不是很麻烦呢?确实是,但是还有一种方法可以解决,将命名空间展开;以上面的命名空间为例,例如以下代码:

		// 将命名空间展开
		using namespace Young;
		using namespace Y;
		
		int main()
		{
			int ret = Add(1, 2);
			printf("%d\n", ret);
		
			struct ListNode node;
		
			printf("%d\n",a);
		
			return 0;
		}

上面的代码就将 Young 和 Y 两个命名空间中的内容展开,就不用再使用域作用限定符了;除此之外,我们还可以展开部分命名空间中的内容,例如,我只展开 Add 函数出来:

		// 展开部分
		using Young::Add;
		
		int main()
		{
			int ret = Add(1, 2);
			printf("%d\n", ret);
		
			struct Young::ListNode node;
		
			printf("%d\n", Young::Y::a);
		
			return 0;
		}

以上就是展开部分的命名空间,通常在做项目的时候,我们都不会将命名空间展开,因为展开就会变得不安全;但是在平常我们在写代码练习的时候,可以将命名空间展开,更有利于我们练习。

二、了解 C++ 中的输入和输出

首先我们先要知道,C++中引入了不同于C语言的输入和输出,在C语言中我们使用 scanf 和 printf 作为输入和输出,但是在C++中了 cout 标准输出对象(控制台)和 cin 标准输入对象(键盘);我们先看看它们的使用:

在这里插入图片描述

我们可以了解到,上述代码中的 cout 和 cin 分别叫做流插入运算符流提取运算符,关于这两个更多的我们在以后的学习中再介绍;其中 cout 和 cin 必须包含< iostream >头文件以及按命名空间使用方法使用 std ,其中 std 是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中。所以我们可以展开 std 的命名空间:

		#include <iostream>
		using namespace std;
		
		int main()
		{
			int input;
			double d;
			// 自动识别类型
			cin >> input >> d;
		
			cout << input << endl << d << endl;
			return 0;
		}

除此之外,cin 和 cout 还可以自动识别变量的类型,如上述代码,它的输出如下图:

在这里插入图片描述

三、缺省参数

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。先看看缺省参数的使用:

在这里插入图片描述
在上面的使用中,Add 函数就是用了缺省参数,在 Add 函数定义中,它指定了 a = 100,b = 200,意思就是,当调用 Add 函数时,如果没有参数传进来,就使用它自己定义的变量;传参时,就使用指定的实参,如下图:

在这里插入图片描述
当然也可以只传一部分参数,但是当出现多个参数时,参数必须从右往左依次来给出,不能间隔着给;例如:

		#include <iostream>
		using namespace std;
		
		int Add(int a = 100, int b = 200, int c = 300)
		{
			return a + b + c;
		}
		
		int main()
		{
			int a = 10, b = 20, c = 30;
		
			int ret = Add(a);
			cout << ret << endl;
			return 0;
		}

以上这段的代码输出结果就是 510 ,那么例如 int ret = Add(a,,c); 这种传参是不允许的。

那么我们可以给缺省参数分类,像上面代码中,Add()这种什么都不传的就叫做全缺省参数;像Add(a)或者Add(a,b)这种只传一部分的就叫做半缺省参数

最后,我们要注意缺省参数不能在函数声明定义中同时出现,如果在函数声明和函数中同时出现,我们只需要在声明中给缺省值即可。

四、函数重载

1. 函数重载的概念

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

		#include <iostream>
		using namespace std;
		
		void Add(int a ,double b)
		{
			// 打印数据方便观察
			cout << "void Add(int a ,double b)" << endl;
		}
		
		
		void Add(double a, int b)
		{
			// 打印数据方便观察
			cout << "void Add(double a, int b)" << endl;
		}
		
		
		int main()
		{
		
			Add(3, 3.14);
			Add(3.14, 3);
			
			return 0;
		}

运行的结果如下:

在这里插入图片描述
以上代码中,我们在函数中打印数据,是为了说明编译器调用了这个函数;我们定义了两个同名的函数,但是它们的参数类型不一样,而我们在使用这两个函数的时候,传的参数也不一样,所以它们会调用各自对应的函数;

2. C++支持函数重载的原理

C++支持函数重载的原理是因为C++有自己的函数名修饰规则
我们知道,.cpp文件或者.c文件在生成可执行程序之前,要经过预处理,编译,汇编,链接的过程,具体回顾往期博客:预处理和程序环境;

其中,C语言在编译过程中,符号汇总将所有.c文件的函数名汇总在一起,注意,是函数名,所以在C语言中,重名的函数名在编译过程中会有冲突,编译不通过;

但是,在C++中的函数名修饰规则中,C++不是用函数名汇总在一起,而是有它自己的修饰规则,具体的修饰规则在不同的编译器有不同的修饰规则,例如:

		void func(int i, double d)
		{}
		
		void func(double d, int i)
		{}

这两个函数,在 g++ 编译器的函数修饰后变成【_Z+函数长度+函数名+类型首字母】,如图:

在这里插入图片描述
在这里插入图片描述
所以它们在编译汇总的时候是可以区分开来的。

五、引用

1. 引用的概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。先看一个简单的例子:

		#include <iostream>
		using namespace std;
		
		int main()
		{
			int a = 10;
			int& b = a;
			return 0;
		}

以上代码中int& b = a;就是在定义引用类型,b 就是 a 的别名,a 和 b 实际上都是指向同一个空间,a 的改变会影响 b ,b 的改变也会影响 a.

2. 引用特性

  1. 引用在定义时必须初始化

  2. 一个变量可以有多个引用

  3. 引用一旦引用一个实体,再不能引用其他实体

     	void Test()
     	{
     		int a = 10;
     		// int& ra;   // 该语句编译时会出错
     		int& ra = a;
     		int& rra = a;
     	}
    

int& ra; 会编译出错是因为在定义时没有初始化;上述代码中,rra 是 ra 的别名,也是 a 的别名,这三个变量用的都是同一个空间,它们之间的互相改变都会影响彼此。

3. 常引用

我们在使用引用时要遵守一条规则,就是在引用的过程中,权限可以平移,权限也可以缩小,但是权限不能放大。例如:

		int main()
		{
			const int a = 0;
			// 权限的放大,不允许
			//int& b = a;
		
			// 不算权限的放大,因为这里是赋值拷贝,b修改不影响a
			//int b = a; 
		
			// 权限的平移,允许
			const int& c = a;
		
			// 权限的缩小,允许
			int x = 0;
			const int& y = x;
		
			return 0;
		}

上述代码中,权限的放大是指,const int a = 0;const修饰的 a 变量具有常性,不可修改,是只读,但是int& b = a;代表 b 的值可修改,并且 b 的值修改会影响 a ,b 是可读可写的,但是 a 只有只读,所以这里是权限的放大;但是int b = a; 不算权限的放大,因为这里是赋值拷贝,b 的修改不影响 a.

权限的平移是指,大家都具有一样的权限,例如上述代码中的const int& c = a;此处的 c 和 a 都被 const 修饰了,大家都具有常性,所以是权限的平移,是可以的。

权限的缩小在上述代码中,int x = 0; const int& y = x;是指 x 是可读可写的,但 y 被 const 修饰了,只有只读,但是从可读可写转变成只读是允许的,这种就叫做权限的缩小。

那么我们看一下以下的语句属于什么呢?

		void test()
		{
			int i = 0;
			double& d = i;
		}

首先我们应该了解清楚,如果是int i = 0; double d = i;也是可以的,因为它们之间会发生整型提升;那么我们要清楚,这个整型提升的过程中,会发生拷贝的过程,d 取的是 i 的临时拷贝,如下图,而这个临时拷贝具有常性,不可被修改,所以这里是权限的放大,是不允许的。
在这里插入图片描述
所以正确的语句应该如下:

		void test()
		{
			int i = 0;
			const double& d = i;
		}

将 d 的属性也变成不可修改,那么它们之间就是权限的平移关系了。

4. 引用的使用场景

(1)做参数(传引用传参)

我们常见的传引用传参就是交换函数了,写一个我们常用的交换函数如下:

		#include <iostream>
		using namespace std;
		
		void Swap(int* p1, int* p2)
		{
			int tmp = *p1;
			*p1 = *p2;
			*p2 = tmp;
		}
		
		int main()
		{
			int a = 10, b = 20;
		
			Swap(&a, &b);
			
			return 0;
		}

在这个交换函数中,我们需要传 a 的地址和 b 的地址过去,才能改变 a 和 b 的值;在C++中,我们可以使用引用完成同样的交换,代码如下:

		void Swap(int& p1, int& p2)
		{
			int tmp = p1;
			p1 = p2;
			p2 = tmp;
		}
		
		int main()
		{
			int a = 10, b = 20;
		
			Swap(a, b);
		
			return 0;
		}

使用了引用后,代码整体看起来就很舒服,不用像指针那样传地址和解引用;同时传引用传参还能提高传参的效率,因为每一次传址或者传值都是一次拷贝,每传一次就要多拷贝一次,效率很低;而引用则不需要拷贝,因为形参是实参的别名,就不用进行拷贝。

除此之外,传引用传参最舒服的地方还是在我们以前学过的单链表中,如往期博客 单链表 中,无论是头插还是尾插等等操作,都需要传二级指针才能改变链表的整体结构,而C++引入了引用之后,就不需要传二级指针了,如下代码:

		void SLTPushBack(SLTNode*& phead, SLTDateType x)
		{
		    // ...
		    if (phead == NULL)
		    {
		        phead = newnode;
		    }
		    else
		    {
		        //...
		    }
		}
		
		int main()
		{
		    SLTNode* plist = NULL;
		
		    SLTPushBack(plist, 1);
		    SLTPushBack(plist, 2);
		    SLTPushBack(plist, 3);
		
		    return 0;
		}

(2)做返回值(传引用返回)

在使用传引用返回时需要注意,不像传引用传参一样,传引用返回如果出了函数作用域对象还在的话才可以用,如果出了函数作用域对象不在就不能用;如以下代码:

		int& func()
		{
			int n = 0;
			n = 10;
		
			return n;
		}
		
		int main()
		{
			int ret = func();
			
			return 0;
		}

在这段代码中,函数 func 内定义了一个变量 n,但是它的生命周期只在这个函数内,出了函数作用域它的空间就会被销毁,画图更好地理解:

在这里插入图片描述
如上图,func 销毁后,n 随之也会销毁,将空间归还给操作系统,但是在 main 函数中,ret 实际上是相当于访问已经销毁的 n ,这严格来说相当于野指针问题了,也就是越界访问。

但是在不同的编译器中,得出的结果却不一样,在 vs2019 中,是可以得到 n 的值,如下图:
在这里插入图片描述

而在 gcc/g++ 的编译器中,却报错了,如下图:
在这里插入图片描述
原因是因为,这取决于栈帧销毁之后,编译器是否会对已经销毁的空间初始化,如果对已经销毁的空间进行初始化,而继续对它进行访问,就是越界,像 gcc/g++ 这样的编译器,很明显在空间回收时会对空间进行初始化,所以造成越界;而 vs2019 则没有严格的检查。

拓展:那如果将代码改成如下,还能编译通过吗?

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

这里将 ret 的接收改成了引用,也就是说,ret 是返回的 n 的别名,我们看执行结果:

在这里插入图片描述
第二次执行是随机值,为什么呢?原因是因为 ret 是 n 的别名,它们公用同一个空间,在执行 cout 语句时,也会发生一系列函数栈帧的创建,所以新的空间会覆盖之前的 func 所在的空间,也就是说,n 的空间被覆盖了,也就是 ret 的空间被覆盖了,所以 n 的值也就变成了随机值;第一次是 10 的原因是原来的空间并没有被覆盖。

所以就引入了另一个话题,如果 n 的空间没有被覆盖,它是不是还是 10 呢?那么我们将代码修改成以下代码:

		int& func()
		{
			int a[1000];
			int n = 0;
			n = 10;
		
			return n;
		}
		
		int main()
		{
			int& ret = func();
			
			cout << ret << endl;
			cout << ret << endl;
		
			return 0;
		}

在 func 函数内,我们增加了一个长度为 1000 的数组,我们先看运行结果:

在这里插入图片描述

这个时候又变成了 10 ,这是因为函数的栈帧中空间是向下创建的,所以在 func 函数内,先创建 1000 个空间,然后再为 n 创建空间,n 这个时候的位置是处于下方的;如果 func 销毁后,如果有新的空间覆盖,这要取决于这个空间是否比原来 func 的空间要大,如果这个空间很大,覆盖了 n ,那么 n 就会变成随机值,否则,n 还是原来的值。

那么传引用返回有什么应用场景呢?我们常见的传引用返回可以用作修改返回对象,例如在单链表中,查找函数和修改函数可以合并在一起写,使用传引用返回,这样就既可以查找到想要查找的数据,又能修改想要修改的值。例如以下代码:

		int& SLFindOrModify(struct SeqList& ps, int i)
		{
			assert(i < ps.size);
			// ...
			return (ps.a[i]);
		}
		
		int main()
		{
			// 定义对象
			struct SeqList s;
			
			// 查找 10 这个数据,并将它修改成 20
			SLFindOrModify(s, 10) = 20;
		
			return 0;
		}

(3)引用和指针的区别

现在我们都学过指针和引用了,我们可以发现,其实引用和指针很相似,在很多用法上指针可以代替引用,引用也可以代替指针,那么它们之间又有什么区别呢?我们一一分析:

引用和指针的不同点:

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

六、内联函数

1. #define定义宏

我们以前学过 #define定义宏,如往期博客 #define定义宏 中,宏给我们带来很多好处,如针对频繁调用的小函数,不需要建立栈帧,提高了效率;如以下代码:

		#define ADD(a,b) ((a)+(b))
		
		int main()
		{
			int ret = ADD(10, 20);
		
			cout << ret << endl;
			return 0;
		}

以上的宏定义了两个数的相加,注意,这里宏定义的((a)+(b))不能写成(a+b),因为考虑到运算符优先级问题,如ADD(1 | 2 + 1 & 2)这种表达式,加号优先级更高,会先执行加的操作,再执行 | 和 & ,并不是我们想要的结果。

上面的宏定义在预处理阶段是直接展开替换,所以没有建立栈帧,很好地提高了效率。

但是宏给我们带来好处的同时,必然会带来不便,如使用宏定义会容易出错,就如上面两数相加的宏,少一个括号都不行,所以宏的语法坑很多。

最后总结一下宏的优缺点:

优点:

  1. 没有类型的严格限制。
  2. 没有函数栈帧的建立,提高效率。

缺点:

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

2. 内联函数的概念

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

例如以下的两数相加的内联函数:

		inline int Add(int a, int b)
		{
			return a + b;
		}
		
		int main()
		{
			int ret = Add(10, 20);
		
			cout << ret << endl;
			return 0;
		}

以上代码中,两数相加的内联函数既没有建立函数栈帧,性能有很好的体现,也没有因为运算符问题需要添加很多括号,所以内联函数是综合了宏和函数的优缺点来设计的。

2. 内联函数的特性

(1) inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。

(2) inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。

也就是说,假设你使用了 inline,编译器也不一定会视这个函数为内联函数,因为如果这个函数的规模很大,代码量大,会造成代码膨胀,所以综合性能方面考虑,我们如果使用内联函数,尽量要简化代码。

(3) inline 不建议声明和定义分离,分离会导致链接错误。因为 inline 被展开,就没有函数地址了,链接就会找不到。

例如我定义了一个 Test.h 的头文件,里面包含 Add 函数的声明:

		inline int Add(int a, int b);

再定义一个 Test.cpp 文件,里面包含 Add 函数的实现:

		#include "Test.h"
		int Add(int a, int b)
		{
			return a + b;
		}

然后在 main.cpp 函数中调用 Add 函数:

		#include "Test.h"

		int main()
		{
			int ret = Add(10, 20);
		
			cout << ret << endl;
			return 0;
		}

最后编译出错了,如下图:

在这里插入图片描述
这是因为什么呢?原因是因为头文件 #include "Test.h" 会在预处理阶段在 main.cpp 文件中展开,展开之后会有函数 Add 的声明,而 Add 函数前加了内联 inline,编译器会认为它就是一个内联函数,认为它就会直接展开,所以在编译阶段没有给它一个有效的地址,也就没有进入符号表;而在 main 函数中调用了 Add 函数,它在符号表中并没有找到自己对应函数的地址,所以会出现链接错误。

七、auto关键字

在 C++11 中,auto 的含义是,auto 声明的变量必须由编译器在编译时期推导而得。也就是说,auto 是一个根据变量自动推导类型的关键字。

例如:

八、基于范围的for循环(C++11)

当我们需要遍历一个数组时,通常使用以下方式:

		int main()
		{
			int arr[] = { 1,2,3,4,5,6,7,8 };
		
			for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
			{
				cout << arr[i] << " ";
			}
		
			return 0;
		}

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此 C++11 中引入了基于范围的 for 循环。for 循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。使用范围 for 我们可以结合上面所学的 auto 关键字结合使用,例如以下代码:

在这里插入图片描述
如果我们需要改变数组中的值,是否像以下代码那样使用呢?

在这里插入图片描述

很明显,答案是不可以的,因为 e 只是数组中的数据的临时拷贝,改变临时拷贝的值不影响数组中原来的值,所以我们要加上引用:

		int main()
		{
			int arr[] = { 1,2,3,4,5,6,7,8 };
		
			for (auto& e : arr)
			{
				e *= 2;
			}
		
			for (auto e : arr)
			{
				cout << e << " ";
			}
			return 0;
		}

加上引用后,e 就是数组中的数据的别名,改变 e 也就是改变数组中的内容。

九、指针空值 nullptr

在早期设计 NULL 空指针时,NULL 实际上就是 0,所以导致有些地方使用 NULL 会造成不明确的函数调用,例如:

在这里插入图片描述
在以上代码中,func 构成函数重载,我们期望的 NULL 是调用 void func(int*) 函数,但是它却调用了另外一个,所以这造成了不明确的函数调用。

所以在 C++11 中,引入了 nullptr,它的类型是无类型指针(void*),这很好地避免了以上的情况,例如下图,nullptr 是调用了具有指针类型的函数:

在这里插入图片描述

最后,C++ 入门的全部内容已经全部分享完啦,感觉对自己有帮助的小伙伴赶紧点赞收藏吧~感谢支持!

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

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

相关文章

ES系列--打分机制

一、文档打分机制 当你通过关键字搜索相关文档时&#xff0c;可能会出现多个文档&#xff0c;这些文档的顺序是通过一个max_score属性的大小从高到低顺序展现出来的&#xff0c;max_score属性就是我们所说的评分。而这个评分是通过一个文档打分机制计算出来的。 二、打分原理 …

第二章 Android 基础--开发基础

文章目录 1.使用真机调试运行2.Android开发涉及的编程语言3.工程目录结构4.编译配置文件 build.gradle5.清单文件6.界面显示与逻辑处理7.Activity创建与跳转8.练习题 本专栏主要在B站学习视频&#xff1a; B站Android视频链接 本视频范围&#xff1a;P9—P16 工程结构、设计规…

DDOS百科:什么是 DDoS 攻击及如何防护DDOS攻击

一、什么是 DDoS 攻击&#xff1f; 当多台机器一起攻击一个目标&#xff0c;通过大量互联网流量淹没目标或其周围基础设施&#xff0c;从而破坏目标服务器、服务或网络的正常流量时&#xff0c;就会发生分布式拒绝服务(DDoS)攻击。 DDoS允许向目标发送指数级更多的请求&#…

什么是 XSS 攻击,攻击原理是什么

什么是 XSS 攻击&#xff1f; XSS&#xff08;Cross-Site Scripting&#xff09;攻击是一种常见的 Web 安全漏洞&#xff0c;其攻击目标是 Web 应用程序中的用户&#xff0c;攻击者通过在 Web 页面中植入恶意脚本&#xff0c;从而实现窃取用户敏感信息、篡改用户数据等目的。 …

一本通12951917:装箱问题

不知道说什么废话好了 题目 装箱问题 描述 有一个箱子容量为V&#xff08;正整数&#xff0c;0&#xff1c;&#xff1d;V&#xff1c;&#xff1d;20000&#xff09;&#xff0c;同时有n个物品&#xff08;0&#xff1c;n&#xff1c;&#xff1d;30)&#xff0c;每个物品…

安卓进程间通信浅谈

Case: /Users/lucas/AndroidStudioProjects/aidldemo-master 一&#xff1a;操作系统 从操作系统原理去看&#xff0c;进程通信主要有三个方法&#xff1a;共享存储、消息传递、管道通信。 二&#xff1a;安卓中的IPC 进程间通信的几种方式&#xff1a;Intent&#xff08;Bu…

华为产品测评官-开发者之声 - ModelArts 真实体验感想

华为产品测评官&#xff0d;开发者之声 - ModelArts 真实体验感想 我先是在6月17日参加了华为在深圳举办的开发者大会&#xff0c;后面看到群里发的"2023华为产品测评官&#xff0d;开发者之声"活动&#xff0c;简单看了一下体验活动的具体事情&#xff0c;感觉好玩…

超声医疗高压功率放大器ATA-4315技术参数

超声波检查或超声诊断&#xff0c;是一种非侵入性的医学检查方法&#xff0c;它利用了声波的高频振动来观察和评估人体内部的器官和组织。它基于不同密度和组织结构中传播的原理。通过将ultrasound(超声波)传递到身体的特定区域&#xff0c;并记录反射回来的声波&#xff0c;我…

flutter开发实战-svga播放svgaplayer_flutter直播礼物特效等效果使用

flutter开发实战-svga播放svgaplayer_flutter直播礼物特效等效果使用 最近开发过程中用到了SVGA进行播放动画&#xff0c;这里记录一下svgaplayer_flutter使用过程。svga可以做一些非常精美的动画&#xff0c;包括直播的刷礼物(火箭、跑车特效动画)等等。 效果图如下 一、SVG…

分区类型ID一键变身!快速改变分区类型ID的简单方法

分区类型ID是什么&#xff1f; 想要改变分区类型ID&#xff0c;先得明白分区类型ID是什么。大多数电脑用户可能只熟悉分区和分区类型&#xff0c;实际上有5种分区类型&#xff1a;主分区、可扩展固件接口&#xff08;EFI&#xff09;、扩展分区、逻辑分区和Microsoft保留分…

百分点科技苏萌受邀出席首届全国统计与数据科学联合会议

7月11-13日&#xff0c;首届全国统计与数据科学联合会议在北京举行&#xff0c;会议由中国现场统计研究会、中国数学会概率统计分 会、全国工业统计学教学研究会和中国商业统计学会联合主办&#xff0c;北京大学统计科学中心承办&#xff0c;旨在促进统计与数据科学领域发展&a…

vuecli5.x 配置图片输出为base64

解释&#xff1a;webpack的默认配置是小于一定的文件大小就要将图片转为base64, 所以尽量将这个阈值调大你的图片就可以转为base64; 当然这种做法不好, 会导致代码文件变大, 不过为了满足需求也没得办法。这年头大家都用 vite 了, 网上没有 vuecli5.x 这方面的记录, 写篇文章记…

Java经典面试解析:服务器卡顿、CPU飙升、接口负载剧增

01 线上服务器CPU飙升&#xff0c;如何定位到Java代码 解决这个问题的关键是要找到Java代码的位置。下面分享一下排查思路&#xff0c;以CentOS为例&#xff0c;总结为4步。 第1步&#xff0c;使用top命令找到占用CPU高的进程。 第2步&#xff0c;使用ps –mp命令找到进程下…

Flink 在新能源场站运维的应用

摘要&#xff1a;本文整理自中南电力设计院工程师、注册测绘师姚远&#xff0c;在 Flink Forward Asia 2022 行业案例专场的分享。本篇内容主要分为四个部分&#xff1a; 建设背景 技术架构 应用落地 后续及其他 点击查看原文视频 & 演讲PPT 一、建设背景 建设背景主要…

农产品后台管理系统(一)——项目总览

后端技术栈 SpringBoot2.xMybatis-plusMysql8.0redisjsoup&#xff08;测试爬取数据&#xff09; 前端技术栈 Vue3EchartsAxios前端组件&#xff1a;element-china-area-data、element-plus 项目概览截图 登录界面 注册界面 农产品发布界面 用户管理界面 用户画像界面 订单…

centos 安装pyzbar

需求&#xff1a; 运行程序报错 ImportError: Unable to find zbar shared library 进程&#xff1a; 直接使用yum 安装 yum install python-devel && yum install zbar-devel 有时候会能成功&#xff0c;大多数时候python-devel 能成功但是 zbar-devel 会失败 下载…

国密算法概述、及算法的集成应用(sm2、sm3、sm4)

国密算法概述、及算法的集成应用&#xff08;sm2、sm3、sm4&#xff09; 一、概述二、分类概述3.1、SM1对称密码3.2、SM2椭圆曲线公钥密码算法3.3、SM3杂凑算法3.4、SM4对称算法3.5、SM7对称密码3.6、SM9标识密码算法3.7、ZUC祖冲之算法 三、集成SM2加解密四、集成SM3加密、验签…

vue3和gin框架实现简单的断点续传

vue3和gin框架实现简单的断点续传 前端代码 Test.vue <template><div><inputtype"file"ref"uploadRef"change"upload"multiple/><templatev-for"item in fileList":key"item.key"><br><…

Grafana_数据可视化工具

目录 一、简介 二、安装部署 1、下载 2、安装 3、启用 三、使用简介 1、添加数据源 2、创建DashBoard 3、查看dashboard 4、选择查看的时间段 5、阈值颜色控制 源码等资料获取方法 一、简介 Grafana是一个跨平台开源的纯html/js编写的度量分析和可视化工具&#x…

如何应用MySQL高阶语句(子查询)

目录 一、SQL高阶语句 常用查询 关键字排序 升序降序 按区域进行查找 分组统计 limit限制显示结果条目 As别名设置 使用场景 嵌套克隆复制表结构 二、通配符 三、子查询 insert子查询 update子查询 delete子查询 Exists检测 一、SQL高阶语句 常用查询 对于MyS…