【C++】—— 从 C 到 C++ (下)

【C++】—— 从 C 到 C++ (下)

六、引用

6.1、什么是引用

  在大家学习C语言指针的部分时,是不是觉得指针特别难学,还有点繁琐,每次使用都要取地址、解引用、还有二级指针什么的。为此,C++引入了引用的语法

  引用并不是新定义一个变量,而是在已有变量的基础上给它取一个别名,编译器不会为引用变量开辟新的内存空间,它和它的引用变量公用一块内存空间。

  什么意思呢?就拿《水浒传》中的任务来说,林冲别名叫豹子头、李逵别名叫黑旋风;林冲和豹子头指向的是同一个人,李逵和黑旋风也是指向同一个人

类型& 应用别名 = 引用对象;

  C++ 中为了避免引入太多的运算符,会复用 C语言 的一些符号比如 <<>>,这里引用也和取地址用了同一个符号 &,大家应注意区分:放在类型后面是引用,放在对象前面是取地址

#include<iostream>
using namespace std;
int main()
{int a = 0;// 引⽤:b和c是a的别名int& b = a;int& c = a;// 也可以给别名b取别名,d相当于还是a的别名int& d = b;++d;cout << &a << endl;cout << &b << endl;cout << &c << endl;cout << &d << endl;return 0;
}

  上述代码中,给 a a a 取别名 b b b,再给 a a a 取另一个别名 c c c,最后再给 a a a 别名 b b b 取别名 d d d
  可以看到是可以给别名取别名

  什么意思呢?
  我们看下面的图就明白了

在这里插入图片描述

   a a a b b b c c c d d d 指的是同一块空间,这块空间放着 0,什么这是这块空间的不同称谓而已,

  我们取地址发现方面的地址都是一样的,也可以印证这一点

在这里插入图片描述

  

6.2、引用在传参的使用

6.2.1、例一

  引用在实践中主要用于 函数的传参返回值 中,引用的使用会比指针更容易方便

  我们写一个交换函数来感受一下
  众所周知,传参分为传值传参传值传参,传值传参仅仅是实参的一份拷贝,要想改变实参的值,必须用传址传参
  而现在,除了用指针来处理,还可以用引用,并且引用比指针更加方便

#include<iostream>
using namespace std;void swap(int& rx, int& ry)
{int temp = rx;rx = ry;ry = temp;
}int main()
{int a = 10;int b = 20;swap(a, b);cout << "a = " << a << endl << "b = " << b << endl;return 0;
}

运行结果:

在这里插入图片描述

  可以看到,交换是成功的

  在void swap(int& rx, int& ry);函数中,传递实参 a a a b b b 后, r x rx rx r y ry ry 就是 a a a b b b别名,既然是别名他们就指向同一块内存空间,对别名 r x rx rx r y ry ry 的修改就是对 a a a b b b 的修改

  可以看到,相比于使用指针,用引用就方便了很多,首先是传参时不用再取地址,函数内部也不用再需要解引用

  

6.2.2、例二

  在一些主要由 C语言 写成的数据结构的书本中,作者会认为指针太难,怕读者难以理解,而使用引用代替指针,以达到简化程序的目的

举个栗子

typedef struct ListNode
{int val;struct ListNode* next;
}LTNode, * PNode;void ListPushBack(PNode& phead, int x)
{PNode newnode = (PNode)malloc(sizeof(LTNode));newnode->val = x;newnode->next = NULL;if (phead == NULL){phead = newnode;} else{//...}
}

  该段代码用 t y p e d e f typedef typedef s t r u c t struct struct L i s t N o d e ListNode ListNode 重命名为 L T N o d e LTNode LTNode s t r u c t struct struct L i s t N o d e ListNode ListNode* 重命名为 P N o d e PNode PNode

void ListPushBack(PNode& phead, int x)

  这段代码中形参PNode& phead我们一起来理解一下
  
  这是链表的尾插函数,当链表中无数据时,尾插相当于头插,是要改变指针 p l i s t plist plist(代码中没写)的指向的.
  因为 p l i s t plist plist 本身是一个指针,因此要传二级指针。这里是用了引用,即给传递过来的 p l i s t plist plist 指针 s t r u c t struct struct L i s t N o d e ListNode ListNode*  p l i s t plist plist 起别名 p h e a d phead phead p l i s t plist plist p h e a d phead phead,这样就不用二级指针了。
  形参 s t r u c t struct struct L i s t N o d e ListNode ListNode * &   p h e a d phead phead,因为将 s t r u c t struct struct L i s t N o d e ListNode ListNode * 重命名 P N o d e PNode PNode,所以是 P N o d e PNode PNode&  p h e a d phead phead

  

6.3、引用在做返回值的使用

  引用做返回值类和对象中有很好的应用,这里我们简单提一下

  现在有一个栈,我们想改变他的栈顶元素,怎么改呢?

void STModityTop(ST& rs, int x)
{rs.a[rs.top - 1] = x;
}

  现在我们可以运用引用做返回值来完成
  我们先来看看传值返回

int STModityTop(ST& rs)
{assert(rs.top);return rs.a[rs.top - 1];
}int main()
{ST st;STInit(st);//初始化栈STPush(st, 1);//插入数据//修改栈顶元素STModityTop(st) = 3;return 0;
}

在这里插入图片描述

  可以看到报错了,显示的是左操作数必须为可修改的左值

  首先我们要知道一个知识点:
  函数的返回值并不是直接返回运算结果,它会将最终要返回的运算结果拷贝到在一个临时对象中(与传值传参类似),这个临时对象再做为函数的返回值,而临时对象具有常性(规定),因此是不能直接修改返回值的。

  所谓临时对象,就是编译器需要一个空间暂存函数、表达式等返回值结果时创建的一个未命名的对象,C++中吧这个未命名的对象叫做临时对象

在这里插入图片描述

  但是,今时不同往日,现在引用来啦

int& STModityTop(ST& rs)
{assert(rs.top);return rs.a[rs.top - 1];
}int main()
{ST st;STInit(st);//初始化栈STPush(st, 1);//插入数据//修改栈顶元素STModityTop(st) = 3;return 0;
}

  函数用引用作为返回值就可以直接修改函数返回值

  这是因为引用做返回值就是返回它的引用,中间没有产生临时对象

在这里插入图片描述

  那既然引用这么好用,那我们能不能全部用引用返回呢?
  可定是不能

int& func()
{int a = 0;return a;
}

  这个函数我返回 a a a 的别名(引用)会怎样?
  要知道 a a a 在出了函数作用域就销毁了,这是返回 a a a 的别名会出现类似野指针一样的情况
  
  上述例子可用引用返回是因为引用返回的对象不会因为出了函数作用域而销毁,它是在上创建的。

  

6.4、引用的特性

  了解了引用的使用,相信大家对引用由了初步的感觉,接下来我们一起来了解一下引用特性

  1. 引用在定义时必须初始化
int main()
{int a = 10;int& b;return 0;
}

在这里插入图片描述

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

    这一点,在前面介绍引用的使用时已经介绍过了,这里就不再介绍了
      

  2. 引用一旦引用一个实体就不能再引用其他实体

我们想一个问题:

void ListPushBack(PNode& phead, int x);void ListPushBack(LTNode&& phead, int x);

  既然可以用一次引用让二级指针变为一级指针,那能不能直接用两次引用 && 替代二级指针呢?

  答案是不能:因为引用时不能改变指向的,而链表这个头结点的指针是需要不断改变指向
同理,链表中的指向下一个节点的变量 n e x t next next 也只能用指针

  指针和引用更多的是 相辅相成 的效果,而不是取代

  

6.5、引用的使用总结

  • 引⽤在实践中主要是于引⽤传参和引⽤做返回值减少拷⻉提⾼效率改变引⽤对象时同时改变被引⽤对象
  • 引⽤传参跟指针传参功能是类似的,引⽤传参相对更⽅便⼀些。
  • 引⽤返回值的场景相对⽐较复杂,我们在这⾥只是简单讲了⼀下场景,还有⼀些内容后续类和对象章节中会继续深⼊讲解。
  • 引⽤和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引⽤跟其他语⾔的引⽤(如Java)是有很⼤的区别的,除了⽤法,最⼤的点,C++引⽤定义后不能改变指向 J a v a Java Java 的引⽤可以改变指向。

  

6.6、 c o n s t const const 引用

6.6.1、 c o n s t const const 引用的规则

在【C语言】—— 指针二 : 初识指针(下)中,我们了解到 c o n s t const const 修饰变量和 c o n s t const const 修饰指针。这里简单回顾一下。

  • c o n s t const const 修饰变量:变量不可被修改,变成只读
  • c o n s t const const 修饰指针:
    • c o n s t const const ∗ * 左边:修饰的是指针所指向的内容,指针所指向的内容不可被修改
    • c o n s t const const ∗ * 右边:修饰的是指针本身,指针的指向不能被修改。

  下面我们来看看 c o n s t const const 引用。

  那我们对 c o n s t const const 修饰的变量进行引用,是不是要用 c o n s t const const 引用呢

int main()
{const int a = 10;const int& ra = a;return 0;
}

在这里插入图片描述

  可以看到编译是通过的

  那如果用普通的引用会发生什么

int main()
{const int a = 10;int& ra = a;return 0;
}

在这里插入图片描述

  可以看到是编不过去的。

  其实也是,我自己本身的访问权限都只是只读,你变成我的别名后你竟然告诉我可以读写,这合理吗?不合理。

这里我们了解一下权限放大权限缩小的概念

  • 权限放大:当某个变量或文件等只有只读的权限,我们赋予它读写的权限,就是权限放大
  • 权限缩小:当某个变量或文件有读和写的权限,我们限制它其中某一项,就是权限缩小

  第二个例子就是权限放大,引用是不允许权限放大的。

  既然权限放大不行,我们试试权限缩小

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

在这里插入图片描述

没有问题!

  C++中规定,对象的访问权限在引用过程中,只能缩小,不能放大

  同时, r a ra ra没有缩小 a a a 的访问权限,用 a a a 访问可读可写,用 r a ra ra 访问是只读

  为什么呢?举个不是很恰当的例子:鲁迅先生,原名周树人,当它是周树人身份时,是个普通人,可以很随意;当他是鲁迅的身份时,他是一个文人,要注意文人的风度,举止就被限制了。这里周树人和鲁迅都是指同一个人,但别名鲁迅相比周树人是权限缩小了的。
  

6.6.2、 c o n s t const const 引用的情况

  了解了 c o n s t const const 引用的规则后,我们来看看下面几种情况
  

6.6.2.1、常量

  我们可不可以对常量取别名呢?听起来很神奇是不是,其实是可以的。

int main()
{const int& ra = 30;return 0;
}

  当然,普通的引用是不行的,常量值只读量,对常量的引用要用 c o n s t const const 引用
  

6.6.2.2、表达式

  除了对常量取别名,给表达式取别名也是可以的

int main()
{int a = 3;int b = 5;const int& c = a * b;return 0;
}

  像是 a + 3 a + 3 a+3 a ∗ b a * b ab 等表达式,他们的计算结果返回值都是存放在一个临时对象中,前面曾提到。临时对象具有常性,即只读性质
  现在我想给它取个名字,要用 c o n s t const const 引用。

	int c = a * b;

  大家思考一下,将表达式的结果赋值给 c c c,这样是权限放大吗?

  不是的,因为这是拷贝,将临时对象的值拷贝到整型 c c c 中,而临时对象本身的权限并没有改变
  这是两块空间,权限放大针对的是同一块空间

const int a = 10;
int b = a;

  同理,这也没有发生权限放大,是将 a a a 空间中的 10 拷贝 b b b 空间中

  

6.6.2.3、隐式类型转换
int main()
{double a = 3.6;int& ra = a;return 0;
}

  这样引用可以吗?是不可以的

  首先我们来看看下面这种情况:

double a = 3.6;
int i = a;

   a a a 是直接赋值给 i i i 吗?不是的,他们中间有个隐式类型转换的过程,它中间会产生一个临时对象进行存储,既然是临时对象,那就要用 c o n s t const const 引用啦

int main()
{double a = 3.6;const int& ra = a;return 0;
}

  因此这样才是对的,这里的 r a ra ra 并不是 a a a,而是中间产生的临时对象

int main()
{double a = 3.6;double& ra = a;return 0;
}

  那这样对吗?是正确
  为什么这里又不用 c o n s t const const 引用呢?
  我们需要搞清楚上面为什么要 用 c o n s t const const 引用
  因为上面发生了隐式类型转换,中间产生了临时对象,用 c o n s t const const 引用的是中间的临时对象
  这里没有产生临时对象,引用的就是 a a a 变量
  
  有小伙伴问这个临时对象销毁了,那这个引用不就出问题了吗?
  不会的,当 c o n s t const const取引用了这个临时对象以后,这个临时对象的生命周期就会跟着这个引用去走
  即 r a ra ra 销毁了,该临时对象才销毁

  

6.7、引用的本质

  在这里,我要告诉大家引用的底层其实是指针

  我们通过观察汇编代码来印证这一点

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

   观看汇编代码方式如下:进入调试模式(按F10),鼠标右键,点击反汇编

在这里插入图片描述

  

在这里插入图片描述

  可以看到,取地址的指令和取别名的汇编指令是一样的;通过解引用修改变量值,与修改别名的汇编指令是一样的。可见引用的底层就是指针

  这里简单讲解一下汇编指令:

  • l e a lea lea 是取地址的意思,00062576 lea eax,[a] 表示取出 a a a 的地址放入 e a x eax eax
  • m o v mov mov 是移动的意思,把逗号右边的值移动给左边,00062579 mov dword ptr [p],eax表示把 e a x eax eax p p p

  虽然引用底层还是指针,但是大家在学习的时候不要往这方面想,应还是按照却别名的思想来理解引用。

  

6.8、指针与引用的关系

  C++ 中指针和引用就像两个性格迥异的亲兄弟,指针是哥哥,引用是弟弟,在实践中他们相辅相成,功能由重叠性,但各有自己的特点,互相不可替代

  • 语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量的地址,要开空间
  • 引用在定义时必须初始化,指针建议初始化,但语法上不是必须
  • 引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象
  • 引用可以直接访问指向对象,指针需要解引用才能访问指向对象
  • s i z e o f sizeof sizeof 含义不同,引用结果为引用类型的大小,但指针始终是地址空间锁占字节个数(32 位平台下占 4 个字节,64 位平台下是 8 字节)
  • 指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些

  

七、 i n l i n e inline inline 内联函数

7.1、引子

  我们都知道,函数调用时会建立栈帧,但建立栈帧是需要额外的开销的。对于一些短小并且需要大量调用的函数,每次调用都要建立栈帧难免效率太低
有什么办法呢?通过【C语言】 —— 预处理详解(上)我们知道,可以运用宏函数

  比如实现一个 ADD宏函数:

#define ADD(int a, int b) return a + b;
#define ADD(a, b) a + b;
#define ADD(a, b) (a + b)

  上面哪个是对的?

  都是错的,正确答案如下:

#define ADD(a, b) ((a) + (b))

  可见,写一个宏函数要注意的点还是很多的,很容易写错

  C++ 看这个宏函数在就不爽了,因此引入了内联函数的概念。

  

7.2、 i n l i n e inline inline 的特点

  用 i n l i n e inline inline 修饰的函数叫做内联函数,编译时 C++ 的编译器会在调用的地方直接展开内联函数,这样函数就不用建立栈帧了,就可以提高效率

  内联函数的定义十分简单,只需要在 正常函数前加上 i n l i n e inline inline 即可。

:展开相当于编译器直接将函数写在主函数中

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

  
  在 d e b u g debug debug 环境下,为了方便调试,内联函数是不展开的,还是会建立栈帧,可以通过以下方法使内联函数展开

在这里插入图片描述

  展开对于编译器来说只是一个建议,也就是说即使加了 inline 编译器并不是一定会将函数展开。这取决于编译器自身,不同的编译器对 i n l i n e inline inline 什么时候展开并不相同,因为 C++ 中并没有规定这个。当代码行数过多编译器就会选择不展开,有可能是 5 行,也可能是 10 行。

  为什么呢?
  想象一下,当函数有 100 行,要调用一万次,那全部展开代码就要增加 一万 ∗ 100 一万*100 一万100 ,而建立栈帧代码永远只有那一份,当调用该函数时再跳到该函数地址。要是这是个递归函数,那就代价更大了,同时也会导致代码膨胀

  注: i n l i n e inline inline 不建议声明和定义分离到两个文件(在同一个文件没问题),分离会导致链接错误。因为 i n l i n e inline inline 被展开,就没有函数地址,连接时就会出现报错

  原因是内联函数编译器是默认不需要地址的,因为它在调用的地方展开了。所以在进行链接的时候,链接器不会把内联函数的地址放进符号表,这样就找不到该内联函数的地址

  内联函数直接声明和定义都放到 . h .h .h 文件,不要声明在 . h .h .h,定义在 . c .c .c

  

八、 n u l l p t r nullptr nullptr 空指针

   在学习 n u l l p t r nullptr nullptr 之前,我们先回顾一下 NULL
  在 C语言 中,定义了一个宏 NULL,在头文件 < s t d d e f . h stddef.h stddef.h> 中可以看到他的定义

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

  在 C++ 中 NULL 其实就是 0,而 C语言 中将 0 强转成 v o i d void void*,即 ( v o i d void void *) 0

  这样定义有什么弊端呢?搞得 C++ 要单独定义一个 n u l l p t r nullptr nullptr

#include<iostream>
using namespace std;
void f(int x)
{cout << "f(int x)" << endl;
} 
void f(int* ptr)
{cout << "f(int* ptr)" << endl;
} 
int main()
{f(0);f(NULL);return 0;
}

在这里插入图片描述

  你会发现都是调用第一个函数,因为 NULL 是宏,替换成 0

  那如果是 C语言 的 ( v o i d void void *) 0 可以吗?会发现编译报错

int main()
{f((void*) 0);return 0;
}

在这里插入图片描述
  你会发现这样也不行,甚至还报错。因为这时要发生隐试类型转换,那是转换成 i n t int int 还是转换成 i n t int int* 呢?

  所以 NULL 不论是 C语言 的定义还是 C++ 的定义都是不好的

  这里顺便说一下,为什么在 C语言 中好像没问题呢?因为 C语言 中的类型检查没有那么严格 v o i d void void* 类型可以隐式转换成其他类型的指针,而 C++ 的类型检查更严格, v o i d void void* 不能隐式转换成其他指针
  
举个栗子:

int main()
{void* p1 = NULL;int* p2 = p1;return 0;
}

  这段代码在 C语言 中是可以编译过去的,但在 C++ 中不行,必须把 p 1 p1 p1 强制类型转换

int main()
{void* p1 = NULL;int* p2 = (int*)p1;return 0;
}

  因此 C++11(C++98中还未引入)中引入 n u l l p t r nullptr nullptr n u l l p t r nullptr nullptr 是一个特殊的关键字 n u l l p t r nullptr nullptr 是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型。使用 n u l l p t r nullptr nullptr 定义空指针可以避免类型转换的问题,因为 n u l l p t r nullptr nullptr 只能被隐式地转换为指针类型,而不能转换为整数类型

int main()
{f(nullptr);return 0;
}

在这里插入图片描述

  使用 n u l l p t r nullptr nullptr 后就没有歧义了,直接调用第二个函数

   以后,C++ 中尽量都用 n u l l p t r nullptr nullptr,不用 NULL

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

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

相关文章

福派斯三文鱼猫粮,养猫新手的福音,让猫咪爱上吃饭!

猫粮的选择对于猫咪的健康和日常饮食至关重要。福派斯三文鱼猫粮作为一款备受关注的产品&#xff0c;它在市场上表现如何呢&#xff1f;下面我们将从几个关键方面深入探讨如何选择猫粮&#xff0c;并详细分析福派斯三文鱼猫粮的优缺点。 一、了解猫咪的独特需求 首先&#xff0…

[Redis]典型应用——分布式锁

什么是分布式锁&#xff1f; 在一个分布式系统中&#xff0c;也会涉及到多个节点访问同一个公共资源的情况。此时就需要通过锁来做互斥控制&#xff0c;避免出现类似于"线程安全"的问题 举个例子&#xff0c;在平时抢票时&#xff0c;多个用户可能会同时买票&#…

ubuntu源码安装Odoo

序言:时间是我们最宝贵的财富,珍惜手上的每个时分 Odoo具有非常多的安装方式&#xff0c;除了我最爱用的 apt-get install&#xff0c;我们还可以使用git拉取Odoo源码进行安装。 本次示例于ubuntu20.04 Desktop上进行操作&#xff0c;理论上在ubuntu14.04之后都可以用此操作。 …

第1关 -- Linux 基础知识

闯关任务 完成SSH连接与端口映射并运行hello_world.py ​​​​ ssh -p 37367 rootssh.intern-ai.org.cn -CNg -L 7860:127.0.0.1:7860 -o StrictHostKeyCheckingno可选任务 1 将Linux基础命令在开发机上完成一遍 可选任务 2 使用 VSCODE 远程连接开发机并创建一个conda环境 …

关于c#的简单应用三题

#region 找出100以内与7有关的数并打印&#xff1a; public static void Print() { int sum 0; Console.WriteLine("100以内与7有关的数有&#xff1a;"); for (int i 1; i < 100; i) { if (i % 7 0) { sum; …

【AI教程-吴恩达讲解Prompts】第1篇 - 课程简介

文章目录 简介Prompt学习相关资源 两类大模型原则与技巧 简介 欢迎来到面向开发者的提示工程部分&#xff0c;本部分内容基于吴恩达老师的《Prompt Engineering for Developer》课程进行编写。《Prompt Engineering for Developer》课程是由吴恩达老师与 OpenAI 技术团队成员 I…

Flink HA

目录 Flink HA集群规划 环境变量配置 masters配置 flink-conf.yaml配置 测试 Flink HA集群规划 FLink HA集群规划如下&#xff1a; IP地址主机名称Flink角色ZooKeeper角色192.168.128.111bigdata111masterQuorumPeerMain192.168.128.112bigdata112worker、masterQuorumPee…

js 实现扫雷游戏,源码开放,支持npm引入使用

本人开发的js版本扫雷游戏 体验地址 | Github Minesweeper game Sponsors Install and use npm i minesweeper-gameimport {Map} from minesweeper-game;const map new Map();Reset Map map.reset();TS Statement interface IMapOptions {width?: number; // Map sizeh…

JMeter:BeanShell向JSR223迁移过程遭遇的java标准库不可用问题-如何切换JDK版本

前言 看过我前面文章的人想必记得我因使用BeanShell&#xff0c;遭遇过JMeter OOM的问题。所以想起官网频频提示的&#xff0c;性能测试中建议使用JSR223groovy来代替BeanShell。于是&#xff0c;开启BeanShell脚本向JSR223迁移之旅。 什么是JSR223 JSR223全称为Java Specif…

Python爬虫(1) --基础知识

爬虫 爬虫是什么&#xff1f; spider 是一种模仿浏览器上网过程的一种程序&#xff0c;可以获取一些网页的数据 基础知识 URL 统一资源定位符 uniform resource locator http: 超文本传输协议 HyperText Transfer Protocol 默认端口 80 https: 安全的超文本传输协议 security…

jenkins+gitlab+harbor+maven自动化容器部署

一、gitlab安装配置 1.1、安装 由于比较懒啊&#xff01;这里就直接使用docker安装了啊&#xff01; 没事先更新一个yum源&#xff1a;yum update -y 整一个gitlab镜像&#xff1a;docker pull gitlab/gitlab-ce 运行一个gitlab容器&#xff1a;docker run -d -p 8443:443 -p…

十七、【机器学习】【非监督学习】- K-均值 (K-Means)

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

[论文笔记] pai-megatron-patch Qwen2-CT 长文本rope改yarn

更改: # Copyright (c) 2024 Alibaba PAI and Nvidia Megatron-LM Team. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License a…

MongoDB常用命令大全,概述、备份恢复

文章目录 一、MongoDB简介二、服务启动停止、连接三、数据库相关四、集合操作五、文档操作六、数据备份与恢复/导入导出数据6.1 mongodump备份数据库6.2 mongorestore还原数据库6.3 mongoexport导出表 或 表中部分字段6.4 mongoimport导入表 或 表中部分字段 七、其他常用命令八…

怎么关闭 Windows 安全中心,手动关闭 Windows Defender 教程

Windows 安全中心&#xff08;也称为 Windows Defender Security Center&#xff09;是微软 Windows 操作系统内置的安全管理工具&#xff0c;用于监控和控制病毒防护、防火墙、应用和浏览器保护等安全功能。然而&#xff0c;在某些情况下&#xff0c;用户可能需要关闭 Windows…

深层神经网络示例

维度说明&#xff1a; A[L]、Z[L]&#xff1a;&#xff08;本层神经元个数、样本数&#xff09; W[L]&#xff1a;&#xff08;本层神经元个数、上层神经元个数&#xff09; b[L]&#xff1a;&#xff08;本层神经元个数、1&#xff09; dZ[L]&#xff1a;dA[L] * g’A&#xf…

【BUG】已解决:ModuleNotFoundError: No module named ‘PIL‘

已解决&#xff1a;ModuleNotFoundError: No module named ‘PIL‘ 目录 已解决&#xff1a;ModuleNotFoundError: No module named ‘PIL‘ 【常见模块错误】 错误原因&#xff1a; 解决办法&#xff1a; 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我…

时序数据库如何选型?详细指标总结!

工业物联网场景&#xff0c;如何判断什么才是好的时序数据库&#xff1f; 工业物联网将机器设备、控制系统与信息系统、业务过程连接起来&#xff0c;利用海量数据进行分析决策&#xff0c;是智能制造的基础设施&#xff0c;并影响整个工业价值链。工业物联网机器设备感知形成了…

《Techporters架构搭建》-Day02 集成Mybatis-plus

集成Mybatis-plus Mybatis-plus集成Mybatis-plus步骤小结 Mybatis-plus Mybatis-plus官网 MyBatisPlus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。它引入了一些新的特性&…

CSRF+XSS组合攻击实战

目录 0x01安装靶场 0x02分析功能点的请求接口&#xff0c;构造恶意请求 0x03寻找xss漏洞 0x01安装靶场 下载源码&#xff0c;解压到网站根目录 1.修改数据库配置文件 打开源码&#xff0c;进入到include目录下&#xff0c;打开数据库配置文件database.inc.php 将数据库的…