[C++] 函数详解
前言
今天zty带来的是函数的详解,搞了4个小时,大家给个赞呗,zty还要上学,发作品会少一点
先 赞 后 看 养 成 习 惯

先 赞 后 看 养 成 习 惯
演示用编译器及其标准
Dev C++ 6.7.5 Red panda C++14
先 赞 后 看 养 成 习 惯
正文
1、函数的概念
什么是函数
在《C++Primer》中对于函数这样说道:
函数是一个命名了的代码块,我们通过调用函数执行相应的代码,函数可以有0个或者多个参数,而且会产生一个结果
对于我的总结:
我觉得函数可以说是一个能够实现一定功能的盒子,把他需要的工具放进去,他给你返回一个结果,可以说函数的内部是一个未知的东西,我们只需要知道这个函数能实现什么样的功能就行了,不需要去知道里面的代码怎么写的。
为什么使用函数
当一个项目或者代码全部紧挨在一起的话,会显得开发十分繁杂,比如一个源文件的main函数中写了很多的代码,前20行实现一个功能,接下来100行实现另一个功能,再300行又实现一个功能…,这样下去,在一个main函数中零零散散地实现了很多功能!但是,过几天反过来再来看源代码,感觉就是脑袋一翁,一个main函数里面写了好几百行代码,不知道这些东西是什么,这样的开发会造成效率的丧失,会让我们没有思路,所以将一个个功能用一个个的函数封装起来,并做好注释,会节省我们很多的开发时间,使得代码可读性,容错性都会大大提高,所以一个良好的使用函数和注释的习惯是一个程序员必备(可以这么说)的品质
2、函数基础
一个函数由以下部分组成
返回类型+函数名(参数列表){代码块}
比如一个代码,求两个数的和并输出
#include<iostream>int main(){int a,b;std::cin>>a>>b; //输入两个数的值int count = a+b;//count为a+b之后的值std::cout<<"两数之和为:"<<count<<'\n'; //输出计算得到的值return 0;
}
在上面的代码中,再main函数中定义了一个求两数之和的程序,所有的计算代码都在main函数里面,下面我们对其加法功能进行一个封装
#include<iostream>void addData(int a,int b){ int count = a+b;//count为a+b之后的值std::cout<<"两数之和为:"<<count<<'\n'; //输出计算得到的值
}int main(){int a,b;std::cin>>a>>b; //输入两个数的值addData(a,b); return 0;
}
我们将求和并输出的代码封装到了一个函数addData中,可以说addData就是实现一个两数相加并输出的功能,对于之后还需要进行两数相加的操作,我们不需要重复地写相加输出代码,只需要调用addData即可,这样不仅提高了代码的可读性,将不同功能进行了区分,而且减少了代码的重复书写,对于一些经常要用到的代码操作,使用函数将这个功能封装起来是一个很好的方法!
3、形参和实参
在函数的编写格式中,在函数名的后面的括号里放入的参数是形式参数
返回类型+函数名(形参列表){…}
上面的代码中,在int addData(int a,int b)里面,这里面的a,b是一个形式参数,可以这么理解,现在这些参数a,b的具体值我不知道。我只知道他是一个整型变量,当在运行函数调用时,传入的才是实际参数,比如main函数中的addData(a,b),此时的a,b是我们输入的已经初始化了的函数,将实际参数放入函数的过程叫做传递参数,即传递具体的值给函数的形式参数,进行特定的操作,它就类似于一个公式一样,你必须给定实际的值,才能得到实际的结果,在传递参数的过程中需要注意几点
- 传入的实际参数必须跟形式参数的类型一样
- 传入的实际参数必须是按照顺序传递的
- 传入的实际参数的数量必须与形式参数的数量相同
//比如前面的addData
addData(3,2); //正确--传递的数量正确
addData(3.0,2); //正确--3.0会强制转换为int类型
addData("321");//错误--传递的类型不正确
addData(2,3,1);//错误--传递的参数数量不对
参数的定义
- 每一个形参之间必须用逗号隔开,并注明类型
- 可以不定义形式参数
- 形式参数可以是任何基本类型或者本身定义的类型,可以是指针,引用,值
int fun();//正确--隐式的定义无形式参数 int fun(void);//正确--显示的定义无形式参数 int fun(int a,b);//错误--每一个形式参数前都要有一个变量类型 int fun(int a int b);//错误--不同的形式参数之间没有用逗号隔开 int fun(int a,int b);//正确--值传递 int fun(int *a,int *b);//正确--指针传递 int fun(int &a,int &b);//正确--引用传递
4、函数的调用
直接调用
直接调用即在代码中调用函数,比如说addData()
嵌套调用
嵌套调用指的是,举一个例子,在a函数中会调用b函数,而在b函数中又调用了a函数
递归调用
递归调用指的是函数内部调用函数自己
5、函数的参数传递
C++函数的传递个人感觉是一个十分骚气的操作,他的值传递不像Java这么简单,如果不了解c++的传值类型,可能有一些方法的调用得到的结果往往不是我们所想的那样
比如设计一个函数
//交换两个变量的值 void swaps(int a,int b){int temp = a;a = b;b = temp; }
你写了一个函数,能够交换两个变量的值,于是在main函数中测试这个函数,却发现输出的结果往往不是我们想象的那样,发现值并没有交换,于是焦头烂额,我这思路没错啊…,到底错在哪里呢,其实是因为c++函数的传值的差异,如果读者有兴趣的话,不妨听我来讲一讲这其中的原因!
int main(){int a,b;cin>>a>>b;cout<<"a的值为:"<<a<<endl;cout<<"b的值为:"<<b<<endl;swaps(a,b);cout<<"a的值为:"<<a<<endl;cout<<"b的值为:"<<b<<endl;return 0; }
值传递
可以知道,每一个变量的定义都会在内存中对应一个地址,每一个地址是对应着特定的编号的,值即这个对应内存地址里面存储的数据,将值作为形式参数传入数组,比如上面main函数的swab(a,b),你以为swap里面用到的a,b就是main函数里面定义的a,b,但是实际不是这样的,可以对函数做一些修改,打印出他的内存地址
void swaps(int a,int b){cout<<"Function Swap address_a is"<<&a<<endl;cout<<"Function Swap address_b is"<<&b<<endl;int temp = a;a = b;b = temp; }int main(){int a,b;cin>>a>>b;cout<<"Address_a"<<&a<<endl;cout<<"Address_b"<<&b<<endl;cout<<"a:"<<a<<endl;cout<<"b:"<<b<<endl;swaps(a,b);cout<<"a:"<<a<<endl;cout<<"b:"<<b<<endl;return 0; }
可以看到,运行结果根本没有交换a,b的值,因为在swap里面的a和b与在mian函数里面输入的a和b地址都不一样,根本就不是同一个变量!所以这样的交换数据的函数根本不是一个可以成功交换的函数,他其实是重新定义了两个int类型变量,只是值与a和b相等,所以值传递并不能达到修改变量的作用,
可以看到当我们在调用函数时传入参数,但是不想改变(非本愿)传入的变量的值时,我们可以采用值传递的形参定义方式
指针传递
相比较于值传递,指针传递又是另外一个方法,指针变量指向的是这个变量存储的内存位置,即指针变量指向内存地址,这个指针变量存储在另一个内存中,通过这个指针,我们可以修改这个指针指向的地址位置的变量数值,对于上面的两数交换的数据,我们就可以用指针传递的形式达到交换两个数据的效果
修改代码如下
#include<bits/stdc++.h> #define ll long long using namespace std; void swaps(int *p, int *q) {cout << "Function swaps Point p Address:" << &p << endl;cout << "Function swaps Point q Address:" << &q << endl;int temp = *p;*p = *q;*q = temp; }int main() {int a, b;cin >> a >> b;int *p = &a, *q = &b;cout << "Point p Address:" << &p << endl;cout << "Point q Address:" << &q << endl;cout << "a:" << a << endl;cout << "b:" << b << endl;swaps(p, q);cout << "a:" << a << endl;cout << "b:" << b << endl;}
从运行结果可以看到,达到了一个交换的效果,以指针的形式,但是可以看到传入的指针跟mian函数里面定义的指针也是不一样的!其实指针传递可以理解为另类的值传递,传递的指针参数也是一个变量类型,在这种swap函数的修改其实是对指针变量指向的内存地址里面的值进行修改,即main函数里面变量a和b的地址里面的值进行修改,也就可以理解为修改了a和b里面的值,这里可以用一张图表明
数组传递
一维数组
数组的传递其实就是指针的传递,当然在C++的STL中有一个可以代替数组的更安全的类型array(这里不考虑),对于c++中的数组类型,其实就是一个指针类型,比如说定义一个数组int a[],这里a就是指向a[0]的指针,要获得a[1],只需要a++即可
//打印数组 void prints1(int a[],int len){for(int i=0,i<len;i++){printf("%d\t",a[i]);}printf("\n"); }void prints2(int *a,int len){for(int i=0,i<len;i++){printf("%d\t",*a);a++;}printf("\n"); } //这两个方法感觉都是指针传递,因为他们都能修改传入的原数组的值int main(){int a[3] = {1,2,3};prints1(a,3);prints2(a,3);return 0; }
可以看到***a和a[]**其实没有区别
二维数组
二位数组其实也没啥,也就是按照一维数组的思想,但是人为的规定了一些限制,因为二维数组数据在内存中是顺序条状存储的,即从1到n个连续的内存位置,存储的是二位数组,计算机才不会管你的几行几列,它只知道只有顺序存储和链式存储之所以有二位数组,是人为的规定了,比如1到多少个内存位置是第一行…,既然这样,同样可以用一个*p来访问二位数组 ,于此同时也可以用双指针(或者说行指针)来访问二位数组
采用一维指针的方式访问
void PrintDoubleArray(int *p,int row,int lie){for(int i = 0;i<row;i++){for(int j = 0;j<lie;j++){printf("%d\t",*p);p++;}printf("\n"); } }
采用二维数组的形式访问
void PrintDoubleArray1(int p[][3],int row,int lie){ for(int i=0;i<row;i++){for(int j=0;j<lie;j++){printf("%d\t",p[i][j]);}printf("\n"); } }
采用行指针的形式访问
void PrintDoubleArray2(int (*p)[3],int row,int lie){ for(int i=0;i<row;i++){for(int j=0;j<lie;j++){printf("%d\t",*((*p+i)+j));}printf("\n"); } }
这三个方法都能够打印出二维数组,但是他们的定义放方式不同
- 一个是采用以为数组,即把二维数组当作一个长一点的一维数组,用指针往后自增来遍历二维数组中的每一个元素
- 另一个是采用索引的方法a[i][j]的形式,来访问二位数组中的每一个元素,但是形式参数的第二个[]里面必须有一个常数,即你传入的二维数组的列数必须是跟形式参数一样的,否则无法传递
- 第三个是以行指针的形式,他的访问方式如下
分类 表示方法 备注 行指针 p+i, *p[i] 下标为第i行的指针 元素指针 *(p+i)+j, p[i]+j 第i行第j列的元素指针 元素 *(*(p+i)+j), *(p[i]+j) 第i行第j列的元素
测试代码,分别用上面三种传值方法输出二维数组
int main(){int a[][3]={{1,2,3},{2,3,4},{3,2,5},{1,5,1}};int *p = &a[0][0];PrintDoubleArray(p,4, 3);cout<<endl;PrintDoubleArray1(a,4,3);cout<<endl;PrintDoubleArray2(a,4,3);return 0;}
可以看到得到的结果是一样的
为参数默认值
在函数中,除了传递变量之外,还可以为设置的形式参数设置默认值,当一个参数具有默认值时,调用其时可以不需要传入该形式参数比如一个函数中的某些参数,我们没有传入时,他是他执行默认的方法,比如一个时间显示器,我们需要传入的参数为时区,当我们没有传入时区时,默认的为北京时间,就显示一个北京时间
void showTime(int opt = 1){switch(opt){case 1:{cout<<"BeJing time:"<<"xxxx.xx.xx.xx\n";break;}case 2:{cout<<"NewYork time:"<<"xxxx.xx.xx.xx\n";break;}} }
然后测试一下
int main(){int des = 2;showTime();showTime(des);return 0; }
可以看到,当没有传入参数时,这个方法将调用形式参数opt的默认值1进行处理,否则按照传入参数进行处理
6、函数的重载
函数的重载的意思即为相同的函数名实现不同的功能,一个相同的函数名他的参数数量,返回类型又可以不同,用来实现其他的功能
比如我们设计一个比较两个变量的大小的函数,可看到
bool compare(int a,int b){return a>b; } bool compare(double a,double b){return a>b; } bool compare(float a,float b){return a>b; }
可以看到,函数名是相同的,但是参数的类型是不同的,他们都实现了一个比较的函数,为了简化上面的代码,我们可以用函数模板来写这个函数,函数模板会在后面介绍,再打个比方,一个物体是有面积的,但是对于不同的物体,传入的参数和求面积的方式是不同的
void area(int r){//求圆的面积cout<<"The area of Circle is:"<<3.14*r*r; } void area(int a,int b){//求矩形的面积cout<<"The area of Rectangle is:"<<a*b; }
可以看到上面的函数定义中,一个area函数能有不同的求面积的方法,参数的数量和类型可以不同,即相同的函数名可以实现很多的方法
7、函数模板
对于上面的compare函数,要实现不同的比较方法,需要重新写很多份代码,这样大大加大了代码的冗余度,为了解决这个问题,其实c++是有一个函数模板编程方法的,即起始我们不知道这个形式参数的具体类型是什么,而是在程序运行的时候将特定的变量代替这个模型,定义的格式为
template<typename T> //T是一个起初未知的模板类型 bool compare(T a,T b){return a>b; }
我们并不知道T的具体类型是什么样子的,但是这样的话可以大大地减少代码的冗余度,这个变量类型T只有在实际的编译运行过程中根据用户的输入变量类型来替代,但是T不能是所有的变量类型,它也是有限制的,是根据代码来确定适配范围的,如果一个类型没有重载>这个运算符,这种类型传入无法比较大小,这是程序运行的过程中是会报错的
8、内联函数和constexpr函数
内联函数
在程序的运行中,一次函数的调用远非我们想象的只是执行几行语句那么简单,假设有这么一个函数
string& shortString(const string &st1,const string &st2){return st1.size()>st2.size()?st2:st1; } //这个函数的意思即为返回两个字符串中长度较小的字符串的引用类型
在shortString函数执行的过程中,并不是简单的return st1.size()>st2.size()?st2:st1;在执行这句话之前,还有着一系列的操作,比如将方法入口拷贝到寄存器,并且在返回时恢复,或者需要拷贝实参,返回返回值…,需要经历一系列的操作之后,上面那一句话只是这一系列操作的一部分,那么对于这些十分简单的函数语句描述,可以用内联函数来实现,内联函数能够避免函数调用的额外开销,将函数指定为内联函数,通常是在每个调用点的内联地址展开,而无需前面的这么多步操作
定义内联函数十分简单,只需要在返回值前面加一个inline即可,上面的方法改为内联为
inline string& shortString(const string &st1,const string &st2){return st1.size()>st2.size()?st2:st1; }cout<<shortString(st1,st2)<<endl; //其实在编译的的过程中变相的执行了 cout<<(st1.size()>st2.size()?st2:st1)<<endl;
需要注意的是
- 内联函数只是一个声明,至于在编译的过程中编译器是否把这个函数当作内联函数还得看编译器的想法,即有时候我们可能觉得这个函数是内联函数,但是编译器在编译的过程中并不这样认为
- 内联机制只适用于语句少,代码体简单的函数,如果函数比较复杂的话,inline就没有作用了
constexpr函数
constexpr函数是指能用于常量表达式的函数,即返回值可以是字面值常量,使用constexpr需要注意
- 返回值和形式参数都必须是字面值类型
- 函数体中有且只有一条return语句
constexpr int new_fun(){return 42;} //一个constexpr函数
constexpr int foo = new_fun(); //一个正确的常量表达式
9、函数的指针
函数指针也是函数调用中的一个方法,可以把函数想象成一个变量,那么对于函数也可以存在指针,函数指针指向某种特定的类型,函数的类型由他的返回值和形参类型共同决定,与函数名无关
定义函数指针
返回类型 (*指针名)(形参列表); //函数指针的定义 //比如对于前面定义的函数shortStirng string& (*st)(const string &st1,const string& st2);//未初始化
初始化函数指针
st = shortString; //st指向名为shortString的函数 st = &shortString; //等价赋值语句:取地址符可选
使用函数指针
string s1 = st("abc","defs"); //调用shortString函数 string s2 = (*st)("abc","defs");//等价的调用 string s3 = shortString("abc","defs");
定义的函数指针必须指向返回类型和形参类型和数量相同的函数,当函数指针为空时可以给他定义为nullptr或者0
string::size_type sunLength(const string &,const string &); bool cstringCompare(const char *,const char*); pf = nullptr; //空指针 pf = 0; //也是空指针的意思 pf = sunLength;//错误--返回类型不同 pf = cstringCompare; //错误--参数类型不匹配
函数和函数指针可以作为函数中的形式参数
函数和函数指针和数组有些类似,可以作为函数的形式参数
void funa(const string *st1,const string &st2,string& st(const string &,const string &)); //函数类型作为形参 void funb(const string *st1,const string &st2,string& (*st)(const string &,const string &));//函数指针类型作为形参,当以函数指针作为形参时,可以直接将函数名作为实参使用,编译器会将这个实参转换为函数指针类型funb("abe","sdass",shortString);
用typedef和decltype用特定的名字代替函数指针和函数名
void a(){} //testfun1和testfun2都是函数类型 typedef bool testfun1(); typedef decltype(a) testfun2; //testfun3和testfun4都是函数指针类型 typedef bool (*testfun3)(); typedef decltype(a) *testfun4;//以函数指针作为形式参数 //等价的传值 void funa(testfun1); //testfun1 == bool testfun1() void funb(testfun2); //testfun2 == void a() void func(testfun3); //testfun3 == bool (*testfun3)() void fund(testfun4); //testfun4 == void (*testfun4)() 即a函数的指针类型
返回指向函数的指针
using F = int (int*,int); //F是一个函数类型 using PF = int(*)(int*,int);//F是一个指针类型 PF f1();//正确--返回类型为PF指针的函数 F f2();//错误--函数不能返回一个函数,只能返回函数的指针 F *f3();//正确
后记
作者:zty郑桐羽呀
联系方式:(不挂了,有事私信)
兄弟们给个赞呗
相关文章:

[C++] 函数详解
前言 今天zty带来的是函数的详解,搞了4个小时,大家给个赞呗,zty还要上学,发作品会少一点 先 赞 后 看 养 成 习 惯 先 赞 后 看 养 成 习 惯 先 赞 后 看 养 成 习 惯 演示用编译器及其…...

AMD CPU下pytorch 多GPU运行卡死和死锁解决
参考链接 https://medium.com/amitparekh/solving-ddp-deadlock-with-multiple-gpus-and-amd-cpus-442186632034 简要说明 AMD的IOMMU和NVIDIA的NCCL不兼容问题导致AMD的IOMMU是BIOS 级组件,它基本上充当将虚拟地址映射到 GPU 上的物理地址的接口,它的全部目的是让 CPU 和 G…...

Swift 开发教程系列 - 第12章:协议与协议扩展
协议(Protocol)是 Swift 的一种重要特性,它定义了实现特定功能的方法、属性或其他要求。通过协议,可以将行为定义从具体实现中分离,使代码更具可读性和扩展性。Swift 的协议支持协议扩展,这一特性允许我们为…...

麒麟V10,arm64,离线安装docker和docker-compose
文章目录 一、下载1.1 docker1.2 docker-compose1.3 docker.service 二、安装三、验证安装成功3.1 docker3.2 docker-compose 需要在离线环境的系统了里面安装docker。目前国产化主推的是麒麟os和鲲鹏的cpu,这块的教程还比较少,记录一下。 # cat /etc/ky…...

NUXT3学习日记二(样式配置、引入组件库、区分在服务端还是在客户端渲染)
上一章已经给大家分享官网下载的nuxt3了,下面正式进入我所要说的内容吧 一、初始化样式 想必大家从我的git下载下来的nuxt3,能看到nuxt.config.ts这个文件了吧。 这里我们有两种css配置方式 1、css:[~/assets/base.scss] 这种方式不能在scss文件中定义…...

FPGA/Verilog,Quartus环境下if-else语句和case语句RT视图对比/学习记录
基本概念 RTL(Register - Transfer - Level)视图:是一种硬件描述语言的抽象层次,用于描述数字电路中寄存器之间的数据传输和操作。在这个层次上,可以看到电路的基本结构,如寄存器、组合逻辑、多路复用器等…...

Javascript高级—闭包问题
闭包问题 循环中赋值为引用的问题 for (var i 1; i < 5; i) {setTimeout(function timer() {console.log(i)}, i * 1000) }解决方法有3种 第一种,使用立即执行函数方式 for (var i 1; i < 5; i) {(fuction(j){setTimeout(function timer() {console.log…...

C#入门 017 字段,属性,索引器,常量
字段,属性,索引器,常量都表示数据 字段 什么是字段 字段(field)是一种表示与对象或类型(类与结构体)关联的变量字段是类型的成员,又称“成员变量,写在类体里面与对象关联的字段亦称“实例字段,表示某个对…...

磐石云语音助手拦截介绍
呼叫中心用户实际应用场景下最高会有超过30%的和语音助手;无声主要是进入了语音信箱;如:“听到滴声后留言”,”漏话提醒““发送请按1,重录请按2”以及拨打过程中客户主动拒接产生的”您拨打的用户正忙“,”关机“”停…...

JSP执行过程及其与Servlet执行效率的比较
JSP(Java Server Pages)和Servlet都是Java Web开发中常用的技术,它们都用于动态生成Web页面。然而,JSP和Servlet在执行过程和效率上存在一些差异。本文将详细探讨JSP的执行过程,并比较JSP与Servlet的执行效率。 一、J…...

open3d
open3d open3d用于 3D 数据处理的现代库。 简介 Open3D 是一个开源库,支持快速开发处理 3D 数据的软件。Open3D 前端公开了一组精心挑选的 C 和 Python 数据结构和算法。后端经过高度优化,并设置为并行化。Open3D 是从零开始开发的,具有一更…...

Vue中优雅的使用Echarts的三种方式
一、原始方法直接使用 1、安装ECharts: npm install echarts --save 2、创建一个Vue公共组件 EChart.vue: <template><div :style"{width: 100%, height: 300px}" ref"chart"></div> </template><scri…...

SpringBoot配置文件/日志
目录 一,SpringBoot配置文件 1,配置文件的格式: 2,properties 3,yml 1,properties与yml的转换 2,读取配置选哪个中的内容 3,单双引号的差异: 4,配置对象: 5,配置集合/配置map 6,yml的优缺点: 二,验证码: 学习目的: 实现样例: 接口定义: 代码总结: 三,日志: 1,概…...

微服务架构面试内容整理-SpringCloud Netflix与Spring Cloud Alibaba比较
Spring Cloud Netflix 和 Spring Cloud Alibaba 都是用于构建微服务架构的解决方案,但它们在设计理念、组件和使用场景上存在一些差异。以下是它们的比较: 1. 服务注册与发现 ● Spring Cloud Netflix:使用 Eureka 作为服务注册和发现的组件。Eureka 是基于 REST 的,适合服…...

JDBC魔法:连接MySQL数据库与数据操作的秘籍
文章目录 一. JDBC介绍二. 数据库驱动1.DriverManager2.Connection3.PreparedStatement4.ResultSet 三. JDBC连接MySQL1. 加载驱动2. 获得连接3. 关闭连接 四. JDBC实现数据新增五. JDBC实现数据删除 一. JDBC介绍 JDBC(Java Database Connectivity)是Ja…...

深入了解Scratch:引导初学者开启编程之旅
引言 在当今数字化时代,编程已不再是成年人的专利,而是一项逐渐向低年龄段普及的技能。Scratch作为一款面向儿童和青少年的图形化编程语言,以其简单易用且充满趣味性的特点,成为了许多初学者学习编程的首选工具。本文将深入探讨S…...

js复制内容到剪切板
复制内容到剪切板 最近预报一个需求需要点击按钮复制当前到行的内容到剪切板, 所以写了这个工具 export function copyText(text: string, prompt: string | null 已成功复制到剪切板!) {if (navigator.clipboard) {return navigator.clipboard.writeText(text).th…...

代码 RNN原理及手写复现
29、PyTorch RNN的原理及其手写复现_哔哩哔哩_bilibili 笔记连接: https://pan.baidu.com/s/1_Sm7ptEiJtTTq3vQWgOTNg?pwd2rei 提取码: 2rei import torch import torch.nn as nn bs,T2,3 # 批大小,输入序列长度 input_size,hidden_size 2,3 # 输入特征大小&a…...

企业官网的在线客服,如何提高效果?
企业官网的在线客服,如何提高效果? 作者:开源呼叫中心系统 FreeIPCC,github地址:https://github.com/lihaiya/freeipcc 提高企业官网在线客服的效果,是提升客户体验、增强客户满意度和忠诚度的关键。一个…...

「实战应用」如何可视化 DHTMLX Scheduler 中的资源工作量?
DHTMLX Scheduler是一个全面的 UI 组件,用于处理面向业务的 Web 应用程序中复杂的调度和任务管理需求。但是,某些场景可能需要自定义解决方案。例如,如果项目的资源(即劳动力)有限,则需要确保以更高的精度分…...

论文阅读《BEVFormer》
BEVFormer: Learning Bird’s-Eye-View Representation from Multi-Camera Images via Spatiotemporal Transformers 目录 摘要1 介绍2 相关工作2.1 基于Transformer的2D感知 摘要 3D视觉感知任务对于自动驾驶系统至关重要,包括基于多相机图像的3D检测和地图分割。…...

sql专题 之 sql的执行顺序
文章目录 sql的执行顺序sql语句的格式实际的执行顺序:虚拟表 vs 数据集虚拟表 结果集总结嵌套查询在sql查询中的执行顺序 前文我们了解了sql常用的语句,这次我们对于这些语句来个小思索 戳这里→ sql专题 之 常用命令 sql的执行顺序 SQL语句的执行顺序是…...

Vue3 -- 基于Vue3+TS+Vite项目【项目搭建及初始化】
兼容性注意: Vite 需要 Node.js 版本 18+ 或 20+。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本。【摘抄自vite官网】 这里我用的node版本是 v18.20.2 创建项目: 创建项目我们可以使用npm、yarn、pnpm、bun …...

CTF-RE: TEA系列解密脚本
// // Created by A5rZ on 2024/10/26. //#ifndef WORK_TEA_H #define WORK_TEA_H#endif //WORK_TEA_H#include <cstdint> #include <cstdio>// 定义TEA加密算法的轮次,一般建议为32轮 #define TEA_ROUNDS 32 #define DELTA 0x9e3779b9// TEA加密函数 v…...

信号量和线程池
1.信号量 POSIX信号量,用与同步操作,达到无冲突的访问共享资源目的,POSIX信号量可以用于线程间同步 初始化信号量 #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); sem:指向sem_t类…...

【人工智能】10分钟解读-深入浅出大语言模型(LLM)——从ChatGPT到未来AI的演进
文章目录 一、前言二、GPT模型的发展历程2.1 自然语言处理的局限2.2 机器学习的崛起2.3 深度学习的兴起2.3.1 神经网络的训练2.3.2 神经网络面临的挑战 2.4 Transformer的革命性突破2.4.1 Transformer的核心组成2.4.2 Transformer的优势 2.5 GPT模型的诞生与发展2.5.1 GPT的核心…...

「QT」几何数据类 之 QPointF 浮点型点类
✨博客主页何曾参静谧的博客📌文章专栏「QT」QT5程序设计📚全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…...

可能是全网第一个MySQL Workbench插件编写技巧
引言 应公司要求,数据库的敏感数据在写入到数据库中要进行加密,但是在测试环境查询数据的时候要手动解密,很不方便,有的时候数据比较多,解密比较麻烦。遂研究了一下如何通过 MySQL Workbench 的插件来实现查询数据一键…...

D62【python 接口自动化学习】- python基础之数据库
day62 SQL 基础 学习日期:20241108 学习目标:MySQL数据库-- 131 SQL基础和DDL 学习笔记: SQL的概述 SQL语言的分类 SQL的语法特征 DDL - 库管理 DDL - 表管理 总结 SQL是结构化查询语言,用于操作数据库,通用于绝大…...

探索美赛:从准备到挑战的详细指南
前言 美国大学生数学建模竞赛(MCM/ICM),简称“美赛”,是全球规模最大的数学建模竞赛之一。它鼓励参赛者通过数学建模来解决现实世界中的复杂问题,广受世界各地大学生的欢迎。本文将详细介绍美赛的全过程,从…...