C++学习——缺省参数、重载函数、引用
目录
前言
一、缺省参数
1.1概念
1.2写法
1.3半缺省
1.4使用
二、重载函数
2.1.概念
2.2类型
2.3参数
2.4顺序
2.5问题
2.6原理
三、引用
1、引用是什么?
2、引用的使用方法
3、引用特性
1、引用在定义的时候必须要初始化
2、一个变量会有多个引用
3、引用一旦引用了一个实体,就不能再引用别的
4、与指针对比
5、使用场景
5.1引用作参数
5.1.1大对象作为引用参数
5.2引用作为返回值
5.2.1使用
5.2.2引用作为返回值的注意点
5.2.3引用返回用于读写修改
5.2.4权限问题
5.2.5总结
总结
前言
缺省参数的含义很好理解,重载函数是一个很有意思的用法,对比C语言有了很大的改变。
我们之前在C语言中学过指针,一个*对应着一个&,分别是解引用和取地址,那么在C++里也有一个类似的但是它只有一个&,通过这种用法这里就不是取地址的意思了,而是引用的意思,而且比较方便容易使用。
一、缺省参数
1.1概念
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参
1.2写法
void Func(int a = 0)//这就是缺省参数
{cout << a << endl;
}
int main()
{Func();//不传参数的时候用函数自己里面的Func(10);//传的时候用显示参数,用指定的参数return 0;
}
这里就是一个缺省参数的写法,比较简单理解。
1.3半缺省
//-----半缺省,从右往左缺省,传参从左往右
void Func(int a , int b = 15, int c = 20)
{cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;
}
int main()
{//Func();Func(1); //1 15 20Func(1,2); //1 2 20可以从左到右传依次传参Func(1,2,3); //1 2 3return 0;
}
半缺省的实现就是从左往右走,没传入参数的就按照函数内的参数输出。
1.4使用
这里是一个栈。
struct Stack
{int* a;int top;int capacity;
};void StackInit(struct Stack* pst,int defaultCapacity=4)
{pst->a = (int*)malloc(sizeof(int) * defaultCapacity);if (pst->a){perror("malloc fail");return;}pst->top = 0;pst->capacity = 4;
}int main()
{struct Stack st;StackInit(&st,100);StackInit(&st);return 0;
}
如果没有defaultCapacity,那就需要不断扩容,效率低下,但我们不知道要申请多少内存,所以先给4个,不够用再扩容,默认情况下开少一点,如果想控制就显示的传入参数。
这里注意:
声明和定义不能同时给缺省,因为这时候就不知道按照谁的来了
二、重载函数
2.1.概念
我们知道C语言不允许同名函数的出现,c++则可以,自动匹配类型,构成重载需要没有歧义。
函数重载是函数中的一种特殊的情况,C++允许在同一作用域中声明几个功能类似的同名函数。这些同名函数形参列表(参数个数或类型或类型顺序)不同,常用来处理实现功能类似数据类型不同的问题,返回值没有要求
2.2类型
//---类型
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, 2.2) << endl;return 0;
}
这里返回的类型不同,传入形参的类型也不同,所以可以实现函数重载,不会报错。
2.3参数
//----参数
void Func()
{cout << "Func()" << endl;
}
void Func(int a)
{cout << "Func(int a)" << endl;
}
一个有参数,一个没有参数,所以可以用函数重载,不会报错。
2.4顺序
//----顺序
//也可以认为是类型不同
void f(int a, char b)
{cout << "f(int a, int b)" << endl;
}
void f(char b, int a)
{cout << "f(int a, int b)" << endl;
}
这里是顺序不同,当然也可以认为是类型不同,因为两个形参的类型发生了变化,所以可以用函数重载,不会报错。
2.5问题
当无参调用的时候就会发生歧义
//----问题:无参调用存在歧义
void f()
{cout << "f()" << endl;
}
void f(int a=0)
{cout << "f(int a=0)" << endl;
}
int main()
{f();//重载调用不明确return 0;
}
这里就会出现一个报错,说是重载调用不明确,也就是不知道用哪一个函数了。所以要注意一下。
2.6原理
实际上,函数重载的实现是和它编译器汇编命名规则有关,C语言为什么不能函数重名,因为在C语言中,汇编函数的命名就是函数本身的名字,没有发生改变,所以肯定会发生冲突。而在C++中,汇编函数的命名是重新用一种函数命名的方法,它结合了形参,使两个函数名发生了不同,所以调用的时候不会发生冲突从而实现了函数重载。
三、引用
1、引用是什么?
引用不是新定义的一个变量,而是给已经存在的变量去一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共同用一块空间。
在C++中,引用是一种别名,用于引用已存在的变量或对象。它允许我们通过一个变量名来访问另一个变量的值,而无需使用指针。
引用通常用于函数参数、函数返回类型、以及作为对象的别名。引用在声明时必须进行初始化,一旦初始化后,它将一直引用同一个对象,无法改变引用的目标。引用在使用上类似于原始变量,但是对引用的操作实际上是对原始变量的操作。引用的主要优点是可以避免拷贝大型对象,提高程序的效率。
什么是别名呢,比如你是李白,你又字太白,所以我可以管你叫李白,也可以管你叫“李太白”,但是这两个名字是否是一个人呢?当然如此,就是一个对象,有不同的叫法。
2、引用的使用方法
我们直接给出代码:
int main()
{int a = 0;int& b = a;int& c = b;a = 10;cout << a << " " << b << " " << c << " " << endl;cout << &a << " " << &b << " " << &c << " " << endl;return 0;
}
这里给出了一个变量a,引用b,也就是a的别名可以是b,引用c,b的别名是c,而b又是a的别名,所以c是a的别名,b和c实际上就是a,这里a赋给10,那么输出来的三个变量也都是10。我们不妨可以运行一下:
我们可以看见都是a的地址,他们也都是10,这就是引用。
3、引用特性
引用这里也有几个要注意的特性:
1、引用在定义的时候必须要初始化
int main()
{int a = 10;int& b;return 0;
}
这里要是不初始化的话就会报错。
2、一个变量会有多个引用
比如我们之前的代码:
int a = 0;int& b = a;int& c = b;
这里a变量就有两个引用,分别是b和c。
3、引用一旦引用了一个实体,就不能再引用别的
int a = 10;
int& b = a;
int c = 5;
int& b = c;
cout << a << " " << b << " " << c << " " << endl;
return 0;
这里我们b先引用了a,然后又定义了一个c的变量,再把b引用c,这时候如果我们运行程序的话,就会发现报错。
4、与指针对比
我们以前可能写过两个数交换的函数,那时候用的是指针交换:
void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}
int main()
{int a = 10;int b = 30;cout << "before::" << a << " " << b << endl;swap(&a, &b);cout << "after::" << a << " " << b << endl;return 0;
}
我们通过两个数的指针传入地址实现传址交换通过交换:
这里我们就可以用C++来实现,因为别名都是一个对象的,所以如果引用传入的参数,那么自函数里的参数就是主函数传入参数的别名,都是同一个变量,变相的实现了传址:
void swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}
int main()
{int a = 10;int b = 30;cout << "before::" << a << " " << b << endl;swap(a, b);cout << "after::" << a << " " << b << endl;return 0;
}
这里运行之后还是符合的:
如果这里是传的指针呢?
void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}
int main()
{int x = 10;int y = 30;int* a = &x;int* b = &y;cout << "before::" << *a << " " << *b << endl;swap(*a, *b);cout << "after::" << *a << " " << *b << endl;return 0;
}
这里就是参数传入的是指针,我们依旧可以用引用来实现:
把指针引用可以吗,当然可以了,请看下面的代码:
void swap(int*& a, int*& b)
{int tmp = *a;*a = *b;*b = tmp;
}
int main()
{int x = 10;int y = 30;int* a = &x;int* b = &y;cout << "before::" << *a << " " << *b << endl;swap(a, b);cout << "after::" << *a << " " << *b << endl;return 0;
}
这里就直接把指针引用了,结果运行后还是之前的:
指针和引用的不同点:
1、引用概念上定义一个变量的别名,指针存储了一个变量地址。
2、引用在定义时必须初始化,指针没有要求
3、引用在初始化时引用了一个实体后,就不能再引用其它实体,而指针可以在任何时候指向任何一个同类型的实体
4、没有NULL引用,但有NULL指针
5、在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台4个字节)
6、引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
7、有多级指针,但是没有多级引用
8、访问实体方式不同,指针需要显示解引用,引用编译器自己处理
9、引用比指针使用起来相对更安全
5、使用场景
5.1引用作参数
引用作为参数就是为了提升效率,针对两种情况最适合用引用来作为参数,第一个是大对象,第二个是深度拷贝对象。深度拷贝是指在拷贝对象时,不仅要复制对象的成员变量的值,还需要为新对象分配独立的内存空间,并将原对象的值复制到新对象的内存空间中。这里先接触大对象,后期再接触深度拷贝。
5.1.1大对象作为引用参数
大对象是什么意思,就是通过sizeof后,比较大的对象。
我们可以用下面的代码进行测试:
struct A { int a[10000]; };
void test1(A a) {}
void test2(A& a){}
void testref()
{A a;//以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)test1(a);size_t end1 = clock();//以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)test2(a);size_t end2 = clock();//分别计算两个函数运行结束后的时间cout << "test1_time::" << end1 - begin1 << endl;cout << "test2_time::" << end2 - begin2 << endl;
}int main()
{testref();return 0;
}
这里定义了一个结构体,里面有一个四万字节的整形数组,定义了两个函数,一个是单独的传值,一个用了引用,这里我们可以通过time库函数计时来看到明显的区别:
可以看到时间效率的快慢,对象越大,代价越大。
5.2引用作为返回值
5.2.1使用
我们先看这一块代码:
int Func()
{static int n = 0;n++;return n;
}
int main()
{int a=Func();return 0;
}
Func函数内变量n是在静态区的,当函数调用后n++,但这里不是直接n赋给了主函数里的a,而是通过一个中间的一个寄存器或者其他临时变量接收,然后再传给a,函数栈帧也销毁。
这样我们就可以知道,中间的步骤也是需要时间的,如何才能绕过中间的寄存器或者临时变量呢?这里就可以用引用作为返回值。
int& Func()
{static int n = 0;n++;return n;
}
int main()
{int a=Func();return 0;
}
函数返回的是n,这里引用了n,赋给了a,所以返回值n就是a的一个别名,直接跳过了中间的一系列操作。
如果不生成临时变量好处就是减少了拷贝,提高了效率,在面对大对象的时候影响会很大
我们同样可以用time库来测试一下效率:
struct A { int a[10000]; };
A a;
A test1() { return a;}//值返回
A& test2() { return a;}//引用返回
void testref()
{//以值作为函数返回值类型size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)test1();size_t end1 = clock();//以引用作为函数返回值类型size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)test2();size_t end2 = clock();//分别计算两个函数运行结束后的时间cout << "test1_time::" << end1 - begin1 << endl;cout << "test2_time::" << end2 - begin2 << endl;
}
这里就是通过值返回和引用返回,运行下来可以看到明显的差距:
5.2.2引用作为返回值的注意点
我们思考一个问题:函数栈帧的创建和销毁应该是在一个作用域内的,如果出了这个作用域,就被系统回收销毁了,那么我们在传值引用的时候会不会出现问题?
答案是有可能会的,而且很不安全,所以一定要谨慎使用,这完全取决于栈帧销不销毁,取决于系统,栈帧不销毁我们就可以用,但如果销毁了我们就只能用传值。
我们在用返回值引用的时候,有以下几种情况可以使用:
1、static静态区变量
2、全局变量
3、malloc内存
5.2.3引用返回用于读写修改
我们定义了一个顺序表,这里用的静态顺序表方便演示:
struct SeqList
{int a[100];size_t size;
};
如果提供一个函数可以对它修改而且还可以获取当前修改的地方,怎么写?
int& SLAt(SeqList& ps, int pos)
{assert(pos < 100 && pos >= 0);return ps.a[pos];
}
通过引用返回就可以实现,这里引用的是当前要修改位置的变量,通过以下操作就可以实现:
int main()
{SeqList s;SLAt(s, 0) = 1;cout << SLAt(s, 0) << endl;SLAt(s, 0) += 5;
}
这里就是表的第0个位置修改成1,第0个位置加上5。
5.2.4权限问题
引用返回也有权限问题,这里先说结论:
引用的过程中,权限不能放大,可以缩小或者平移
//引用的过程中,权限不能放大const int a = 0;int& b = a;
这里原来a是常变量,引用后是一个没有限制的整形,所以权限发生了变大,是不能的。
// //引用过程中,权限可以平移或者缩小int x = 0;int& y = x;
还有一种就是修改的 方法:
int& y = x;const int& z = x;//缩小的是z作为别名的权限,x作为别名z的时候不能修改,当为x的时候可以修改,这里可以修改x,y来改变z,但是不能通过z来改变
这里z因为是常量,所以不能进行修改,但是可以通过x来修改,可以通过x和y来修改z的值。
下面这段代码可不可以运行,可以,因为会发生整形提升:
int main()
{double dd = 1.11;int ii = dd;
}
当我们用引用呢?
int main()
{double dd=1.11;int& rii = dd;//const int& rii = dd;
}
答案是不能。也许你会想以你为是因为不同类型的原因,当然这也是一部分原因,但还有另一部分原因,就是在这里不同类型赋值的时候,中间会出现一个临时变量,而这个临时变量是有常性的,所以不能。如果给上一个const就可以实现。
5.2.5总结
1、基本任何场景都可以用引用传参
2、谨慎用引用做返回值,出了函数作用域,对象不在了,就不能用引用返回,还在就可以用引用返回.
总结
今天主要对缺省参数进行了了解,重载函数进行了了解,重点对引用进行了学习。
相关文章:

C++学习——缺省参数、重载函数、引用
目录 前言 一、缺省参数 1.1概念 1.2写法 1.3半缺省 1.4使用 二、重载函数 2.1.概念 2.2类型 2.3参数 2.4顺序 2.5问题 2.6原理 三、引用 1、引用是什么? 2、引用的使用方法 3、引用特性 1、引用在定义的时候必须要初始化 2、一个变量会有多个引用…...

web-JSON Web Token-CTFHub
前言 在众多的CTF平台当中,作者认为CTFHub对于初学者来说,是入门平台的不二之选。CTFHub通过自己独特的技能树模块,可以帮助初学者来快速入门。具体请看官方介绍:CTFHub。 作者更新了CTFHub系列,希望小伙伴们多多支持…...
langchain教程-11.RAG管道/多轮对话RAG
前言 该系列教程的代码: https://github.com/shar-pen/Langchain-MiniTutorial 我主要参考 langchain 官方教程, 有选择性的记录了一下学习内容 这是教程清单 1.初试langchain2.prompt3.OutputParser/输出解析4.model/vllm模型部署和langchain调用5.DocumentLoader/多种文档…...

Postgresql的三种备份方式_postgresql备份
这种方式可以在数据库正在使用的时候进行完整一致的备份,并不阻塞其它用户对数据库的访问。它会产生一个脚本文件,里面包含备份开始时,已创建的各种数据库对象的SQL语句和每个表中的数据。可以使用数据库提供的工具pg_dumpall和pg_dump来进行…...
WebAssembly:前后端开发的未来利器
引言 在互联网的世界里,前端和后端开发一直是两块重要的领域。而 JavaScript 长期以来是前端的霸主,后端则有各种语言诸如 Java、Python、Node.js、Go 等等。然而,近年来一个名为 WebAssembly (Wasm) 的技术正在逐渐改变这一格局。它的高性能…...

Mac下使用brew安装go 以及遇到的问题
首先按照网上找到的命令进行安装 brew install go 打开终端输入go version,查看安装的go版本 go version 配置环境变量 查看go的环境变量配置: go env 事实上安装好后的go已经可以使用了。 在home/go下新建src/hello目录,在该目录中新建…...
【Leetcode 每日一题】47. 全排列 II
问题背景 给定一个可包含重复数字的序列 n u m s nums nums,按任意顺序 返回所有不重复的全排列。 数据约束 1 ≤ n u m s . l e n g t h ≤ 8 1 \le nums.length \le 8 1≤nums.length≤8 − 10 ≤ n u m s [ i ] ≤ 10 -10 \le nums[i] \le 10 −10≤nums[i]≤…...

车型检测7种YOLOV8
车型检测7种YOLOV8,采用YOLOV8NANO训练,得到PT模型,转换成ONNX,然后OPENCV的DNN调用,支持C,python,android开发 车型检测7种YOLOV8...

C语言按位取反【~】详解,含原码反码补码的0基础讲解【原码反码补码严格意义上来说属于计算机组成原理的范畴,不过这也是学好编程初级阶段的必修课】
目录 概述【适合0基础看的简要描述】: 上述加粗下划线的内容提取版: 从上述概述中提取的核心知识点,需背诵: 整数【包含整数,负整数和0】的原码反码补码相互转换的过程图示: 过程详细刨析:…...

面对全球化的泼天流量,出海企业如何观测多地域网络质量?
作者:俞嵩、白玙 泼天富贵背后,技术挑战接踵而至 随着全球化进程,出海、全球化成为很多 Toc 产品的必经之路,保障不同地域、不同网络环境的一致的用户体验成为全球化应用的不得不面对的问题。在跨运营商、跨地域的网络环境中&am…...
『python爬虫』获取免费IP代理 搭建自己的ip代理池(保姆级图文)
目录 1. 环境搭建2. 获取爬虫ip3. 启动本地flask api接口服务4. 封装方法例子代码5. 自定义抓取免费ip的代理站规则6. 自定义规则示例总结欢迎关注 『python爬虫』 专栏,持续更新中 欢迎关注 『python爬虫』 专栏,持续更新中 1. 环境搭建 这边建议python3.7-3.11版本,redis …...
21.命令模式(Command Pattern)
定义 命令模式(Command Pattern) 是一种行为型设计模式,它将请求封装成一个对象,从而使您可以使用不同的请求、队列、日志请求以及支持撤销操作等功能。命令模式通过将请求(命令)封装成对象,使…...

深入探索 C++17 特征变量模板 (xxx_v)
文章目录 一、C++类型特征的前世今生二、C++17特征变量模板闪亮登场三、常见特征变量模板的实际应用(一)基本类型判断(二)指针与引用判断四、在模板元编程中的关键作用五、总结与展望在C++的持续演进中,C++17带来了许多令人眼前一亮的特性,其中特征变量模板(xxx_v)以其…...

【Day32 LeetCode】动态规划DP Ⅴ 完全背包
一、动态规划DP Ⅴ 完全背包 1、完全背包理论 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和…...

景区如何打造高质量游览观光车,提高人流量?
景区如何打造高质量游览观光车,提高人流量? 在旅游业蓬勃发展的今天,各大景区迎来了前所未有的游客热潮。尤其是在春节、五一、国庆等节假日期间,游客数量更是激增。作为景区交通的重要组成部分,游览观光车不仅承载着…...

【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题
【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题 零、起因 最近在使用Ubuntu虚拟机编译ARM程序,解压ARM的GCC后想要启动,报“没有那个文件或目录”,但是文件确实存在,环境配置也检查过了没问题,本文记…...

蓝桥杯之c++入门(六)【string(practice)】
目录 练习1:标题统计方法1:一次性读取整行字符,然后统计方法2:按照单词读取小提示: 练习2:石头剪子布练习3:密码翻译练习4:文字处理软件练习5:单词的长度练习6࿱…...

go的sync包学习
包含了sync.Mutex,sync.RWMutex,sync.Cond,sync.Map,sync.Once等demo sync.Mutex //讲解mutex import ("fmt""math/rand""sync""time" )type Toilet struct {m sync.Mutex } type Person struct {Name string }var DateTime "2…...
互联网上常见的,ip地址泛播什么意思
互联网上常见的,ip地址泛播什么意思! 泛播通过将IP地址广播发送到网络中的所有设备,使得这些设备能够接收到相关信息。例如,DHCP服务器在局域网中广播提供IP地址的请求,以便新设备能够获取一个可用的IP地址。此外&…...

Linux/C高级(精讲)----shell结构语句、shell数组
shell脚本 功能性语句 test 可测试对象三种:字符串 整数 文件属性 每种测试对象都有若干测试操作符 1)字符串的测试: s1 s2 测试两个字符串的内容是否完全一样 s1 ! s2 测试两个字符串的内容是否有差异 -z s1 测试s1 字符串的长度是…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...