13 学习总结:指针 · 其一

目录

一、内存和地址

(一)内存

(二)内存单元

(三)地址

(四)拓展:CPU与内存的联系

二、指针变量和地址

(一)创建变量的本质

(二)取地址操作符:&

(三)指针变量和解引用操作符:*

1、指针变量

2、指针变量的理解

(1)【int* pa】的理解

(2)【int*】的理解

3、解引用操作符:*

(四)指针变量的大小

三、指针变量类型的意义

(一)解引用操作时,决定可以操作多少个字节

(二)指针 + -  整数时,向前/向后走多大的区别

(三)void* 指针

四、const修饰指针

(一)const修饰变量

(二)const修饰指针变量

五、指针的运算

(一)指针 + 或 -  整数

(二)指针 - 指针

(三)指针的关系运算(指针的比较)

六、野指针

(一)野指针造成的原因

1、指针未初始化

2、指针越界访问

3、指针指向的空间释放

(二)如何规避野指针

1、指针初始化

2、小心指针越界

3、指针变量不再使用时,及时置NULL,指针使用之前检查有效性

4、避免返回局部变量的地址

七、assert断言

八、指针的使用和传址调用

(一)指针的使用:strlen的模拟实现

(二)传值调用和传址调用


一、内存和地址

(一)内存

        又称内存储器或主存储器,计算机中所有程序的运行都在内存中进行,计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,这样使用内存则需要高效地管理内存空间;

(二)内存单元

        就是把内存划分为一个个的内存单元,每个内存单元的大小取1个字节(8个比特位),每个内存单元都有⼀个编号,有了这个内存单元的编号,CPU就可以快速找到⼀个内存空间;

(三)地址

        在计算机中我们把【内存单元的编号】也称为【地址】,C语言中给【地址】起了新的名字叫:【指针】

        可以理解为:【内存单元的编号 == 地址 == 指针】

(四)拓展:CPU与内存的联系

        有三条总线将CPU与内存连接彼此,交换数据:①地址总线;②数据总线;③控制总线

        交换过程:地址信息通过【地址总线】被下达给内存,在内存上就可以找到相应的数据,将数据通过【数据总线】传入CPU做处理,【控制总线】则负责传递对数据的操作,如读操作、写操作等

二、指针变量和地址

(一)创建变量的本质

        创建变量的本质是在内存中申请空间,例如创建一个 int 变量就是向内存申请4个字节的空间,每个字节都有自己的编号(地址),变量的名字仅仅是给程序员看的,编译器不看名字,编译器是通过地址找内存单元的

(二)取地址操作符:&

         使用:拿到变量的地址

        例如:

int a = 10;&a;

        &a 就可以拿到变量a的地址,虽然整型变量占用4个字节,我们只要知道了第⼀个字节地址,春藤摸瓜访问到4个字节的数据也是可行的

        注:当一个变量占多个内存单元的时候,总会取出该变量的第一个内存单元(地址较小的那个字节)

(三)指针变量和解引用操作符:*

1、指针变量

        通过取地址操作符(&)拿到的地址是⼀个数值,比如:0x0012ff40,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放在哪里呢?答案是:指针变量中,例如:

#include <stdio.h>
int main()
{int a = 10;int * pa = &a;//取出a的地址并存储到指针变量pa中return 0;
}

        指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址

2、指针变量的理解

        上面例子的写法中的 int *pa 拆开来理解:

(1)【int* pa】的理解

        ①【int *】是变量pa的类型;

        ② pa是一个变量,用来存放地址(指针)的,所以pa又叫指针变量

(2)【int*】的理解

        ① * 表示pa是指针变量;

        ② int 表示【pa 指针变量中保存的地址】所指向的【变量 a】的类型是int

3、解引用操作符:*

        又称为间接访问操作符,用法:

如下演示:
int main()
{int a = 100;int* pa = &a;*pa = 0;此处*pa == a,相当于对a进行修改return 0;
}

        总结:通过【指针变量pa】找到指向的变量a—— *pa(通过pa的值,找到a)

        ① pa —— 指针变量

        ② &pa —— 指针变量pa的地址

        ③ *pa —— pa指向的变量a

(四)指针变量的大小

        【指针变量类型的大小】取决于【地址的大小】,而地址大小由计算机是32位操作系统还是64位操作系统决定

        ① 指针变量是用来存放地址的,一个地址的存放需要多大空间,那么指针变量类型就是多大,所以32位平台总共有32根地址总线,每根线的电信号转化成数字信号后是1或0,那我们把32根地址总线产生的2进制序列作为一个地址,那么一个地址就是32个比特位,就是4个字节;同理,在64位的机器中,一个地址的大小就是8字节

        ② 地址的大小与【指向的原变量的类型大小】无关,就是4字节或者8字节

#include <stdio.h>//指针变量的⼤⼩取决于地址的⼤⼩
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)int main()
{printf("%zd\n", sizeof(char *));printf("%zd\n", sizeof(short *));printf("%zd\n", sizeof(int *));printf("%zd\n", sizeof(double *));return 0;
}

        X86环境输出结果如下:

        X64环境输出结果如下:

        结论:

32位平台下地址是32个bit位,指针变量大小是4个字节

64位平台下地址是64个bit位,指针变量大小是8个字节

指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的

三、指针变量类型的意义

        指针变量的大小和类型无关,只要是指针变量,在同⼀个平台下,大小都是⼀样的,都是4字节或者8字节,为什么还要有各种各样的指针类型呢?

(一)解引用操作时,决定可以操作多少个字节

        如下演示:

#include <stdio.h>
int main()
{int a = 0x11223344;int* p = &a;*p = 0;return 0;
}

        变量a的地址与4个字节的值如下:

        经过 *p = 0;的语句后,4个字节的值全部改为0,如下:

        若代码中指针变量的类型改为char*:

#include <stdio.h>
int main()
{int a = 0x11223344;char* p = &a;*p = 0;return 0;
}

        变量a的地址与4个字节的值如下:

        经过 *p = 0;的语句后,4个字节的值只有一个字节改为0,如下:

      

        结论:指针的类型决定了,解引用操作时,决定可以操作多少个字节

        比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节

(二)指针 + -  整数时,向前/向后走多大的区别

        如下代码演示:

#include <stdio.h>
int main()
{int n = 10;char *pc = (char*)&n;int *pi = &n;printf("%p\n", &n);printf("%p\n", pc);printf("%p\n", pc+1);printf("%p\n", pi);printf("%p\n", pi+1);return 0;
}

        代码结果如下:

        从结果可以得出:char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节;

        结论:指针的类型决定了指针向前或者向后走一步有多大(距离)           

 补充:
        int* pa;   
        pa+1——> +1 * sizeof (int)
        pa+n——> +n * sizeof (int)

        char* pa;   
        pa+1——> +1 * sizeof (char)
        pa+n——> +n * sizeof (char)

总结:

        类型* 变量名;

        变量名 + 1 ——> +1 * sizeof(指针指向的变量类型)

(三)void* 指针

        void* ——无具体类型的指针(泛型指针)

        可以接收任何类型的地址,但是正因为他是泛型指针,所以没有特定类型指针的用法,即无法解引用和进行指针的 + - 操作

        作用:⼀般 void* 类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果,使得⼀个函数来处理多种类型的数据

四、const修饰指针

(一)const修饰变量

        const修饰变量的时候,叫:常变量;

        本质还是变量,只是不能被修改;

        变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量,若不想变量被直接修改,就使用const修饰变量起限制作用

#include <stdio.h>
int main()
{int m = 0;m = 20;//m是可以修改的const int n = 0;n = 20;//n是不能被修改的return 0;
}

        上述代码中n是不能被修改的,其实n本质是变量(无法在数组长度中使用),只不过被const修饰后,在语法上加了限制,只要我们在代码中对n进行修改,就不符合语法规则,就报错,致使没法直接修改n

        但是可以拿到n的地址,通过指针对它进行修改,但这是在打破语法规则

int main()
{const int n = 0;printf("n = %d\n", n);int*p = &n;*p = 20;printf("n = %d\n", n);return 0;
}

        结果如下:

        这里的初衷是不让变量改变,但是通过指针还是能打破const的限制,接下来就要对这一象限改进,直接对指针变量做const限制

(二)const修饰指针变量

        ⼀般来讲const修饰指针变量,可以放在 * 的左边,也可以放在 * 的右边,意义是不⼀样的

int * p;//没有const修饰
int const * p;//const 放在*的左边做修饰
int * const p;//const 放在*的右边做修饰

        如下代码演示:

        代码一:

int a = 10;
int b = 20;
int const * p = &a;*p = 200;err
p = &b;√

        代码一分析:

        这个const限制的是 *p,即p指向的变量a不能改变;但是并没有限制p,所以可以修改p所指向的变量;
        放在*的左边,限制的是指针指向的内容,也就是不能通过指针变量来修改它所指的内容;但是指针变量本身可以改变的

        代码二:

int a = 10;
int b = 20;
int * const p = &a;*p = 200;√
p = &b;err

        代码二分析:

        放在*的右边,限制的是指针变量本身,也就是指针变量本身不可以改变,但可以通过指针变量来修改它所指的内容

        结论:const修饰指针变量的时候

const如果放在 * 的左边,修饰的是【指针指向的内容 *p】,保证指针指向的内容不能通过指针来改变,但是【指针变量本身 p】的内容可变;
const如果放在*的右边,修饰的是【指针变量本身 p】,保证了指针变量的地址指向不能修改,但是【指针指向的内容*p】,可以通过指针改变

五、指针的运算

        指针的基本运算有三种,分别是:

        • 指针 + 或 -  整数

        • 指针 - 指针

        • 指针的关系运算(指针的比较)

(一)指针 + 或 -  整数

        因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺腾摸瓜就能找到后⾯的所有元素

int arr[10] = {1,2,3,4,5,6,7,8,9,10};

#include <stdio.h>
//指针+- 整数
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int *p = &arr[0];int sz = sizeof(arr)/sizeof(arr[0]);for(int i = 0; i < sz; i++){printf("%d ", *(p+i));//p+i 这⾥就是指针+整数}return 0;
}

        注意:指针运算是指对 p 进行运算,而不是对*p,若对 *p 运算,就是对变量a运算了

        在数组中,指针能够“顺腾摸瓜”的原因是:

        ①指针类型决定了【指针+1】的步长,和指针解引用之后的权限;

        ②数组在内存中的地址是连续的

        错误演示代码:

int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};char *p = &arr[0];int sz = sizeof(arr)/sizeof(arr[0]);for(int i = 0; i < sz; i++){printf("%d ", *p);p += 4;}return 0;
}

        代码分析:

        每次打印时,都让p += 4,在打印1~10时恰好正确,

        每次访问都只会访问第一个字节,后面三个字节是直接跳过的,所以两位数的时候是正确的,但是数字大一些就会忽略掉第二个字节的数字,就会出错

(二)指针 - 指针

        【指针 - 指针】的运算前提条件两个指针指向的是同一个空间,否则运算无意义;

        指针 - 指针的【绝对值】,是指针和指针之间【元素的个数】

        应用:求字符串长度 ,如下代码演示:

#include <stdio.h>int my_strlen(char *s)
{char *p = s;//设置尾指针while(*p != '\0' )p++;return p-s;
}int main()
{printf("%d\n", my_strlen("abc"));return 0;
}

        拓展:指针 + 指针?

        答:无意义,类似于 【日期 +- 天数(计算日期)】、【日期 - 日期(算的是两个日期之间差多少天)】有意义,而【日期 + 日期】无意义

(三)指针的关系运算(指针的比较)

        应用:做判断条件使用,数组中,若一个地址小于另一个地址,则执行语句

#include <stdio.h>int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int *p = &arr[0];int sz = sizeof(arr)/sizeof(arr[0]);while(p<arr+sz) //指针的⼤⼩⽐较{printf("%d ", *p);p++;}return 0;
}

六、野指针

        概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

(一)野指针造成的原因

1、指针未初始化

        指针变量也是局部变量,不初始化就会给随机值;

        如果将未初始化的指针变量的值作为地址来进行解引用操作,就会形成非法访问

#include <stdio.h>int main()
{ int *p;//局部变量指针未初始化,默认为随机值*p = 20;return 0;
}

2、指针越界访问

#include <stdio.h>int main()
{int arr[10] = {0};int *p = &arr[0];int i = 0;for(i=0; i<=11; i++){//当指针指向的范围超出数组arr的范围时,p就是野指针*(p++) = i;}return 0;
}

3、指针指向的空间释放

#include <stdio.h>int* test()
{int n = 100;return &n;
}int main()
{int* p = test();printf("%d\n", *p);return 0;
}

(二)如何规避野指针

1、指针初始化

        如果明确知道指针指向哪里就直接赋值地址,如果不知道指针应该指向哪里,可以给指针赋值NULL,NULL 是C语言中定义的⼀个标识符常量,值是0(这个0在C语言中会被强制转化为void*类型),0也是地址,这个地址是无法使用的,读写该地址会报错

        演示代码如下:

#include <stdio.h>
int main()
{int num = 10;int* p1 = &num;int* p2 = NULL;return 0;
}

2、小心指针越界

        ⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问

3、指针变量不再使用时,及时置NULL,指针使用之前检查有效性

        当指针变量指向⼀块区域的时候,我们可以通过指针访问该区域,后期不再使用这个指针访问空间的时候,我们可以把该指针置为NULL;因为约定俗成的⼀个规则就是:只要是NULL指针就不去访问,同时使用指针之前可以判断指针是否为NULL

        演示代码如下:

int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int *p = &arr[0];for(int i = 0; i<10; i++){*(p++) = i;}//此时p已经越界了,可以把p置为NULLp = NULL;//下次使⽤的时候,判断p不为NULL的时候再使⽤//...p = &arr[0];//重新让p获得地址if(p != NULL) //判断{//...}return 0;
}

4、避免返回局部变量的地址

        不要返回局部变量的地址

七、assert断言

        

        assert.h 头文件定义了宏 assert ( ) ,用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行,这个宏常常被称为“断言”

        使用:#include <assert.h>;assert(表达式)

        作用:判断是否符合指定条件,如果不符合就会终止运行;【通常用来判断指针变量的有效性】

        判断:判断为真则程序继续向下走,判断为假则报错

int* p = NULL;
...
assert(p != NULL); 
此处经过一些列的代码后,若 p 不等于NULL则正常运行下去,若还是等于NULL,则程序报错,终止运行

        若想取消assert断言,则在#include <assert.h>上面 #define NDEBUG;

        assert断言只在Debug版本中有效,在Release版本中会被优化掉

        缺点:引入了额外的检查,增加了程序的运行时间

八、指针的使用和传址调用

(一)指针的使用:strlen的模拟实现

        库函数strlen的功能是求字符串⻓度,统计的是字符串中 \0 之前的字符的个数

        函数原型如下:

size_t strlen ( const char * str );

        参数str接收⼀个字符串的起始地址,然后开始统计字符串中 \0 之前的字符个数,最终返回长度;

        如果要模拟实现只要从起始地址开始向后逐个字符的遍历,只要不是 \0 字符,计数器就+1,这样直到 \0 就停止,代码如下:

size_t my_strlen(const char * str)
{int count = 0;assert(str);//为了保险,判断传来的是不是空地址while(*str){count++;str++;}return count;
}int main()
{size_t len = my_strlen("abcdef");printf("%zd\n", len);return 0;
}

        注:代码中的 const(不希望原值被修改)和 assert(保险判断)来加强代码使用时的健壮性(鲁棒性)
 

(二)传值调用和传址调用

        传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用,如果函数内部要修改主调函数中的变量的值,就需要传址调用


        以上内容仅供分析,若有错误,请多多指正

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

SAP已下发EWM的交货单修改下发状态

此种情况针对EWM未接收到ERP交货单时&#xff0c;可以使用此程序将ERP交货单调整为未分配状态&#xff0c;在进行调整数据后&#xff0c;然后使用VL06I&#xff08;启用自动下发EWM配置&#xff0c;则在交货单修改保存后会立即下发EWM&#xff09;重新下发EWM系统。 操作步骤如…

Kaggle网站免费算力使用,深度学习模型训练

声明&#xff1a; 本文主要内容为&#xff1a;kaggle网站数据集上传&#xff0c;训练模型下载、模型部署、提交后台运行等教程。 1、账号注册 此步骤本文略过&#xff0c;如有需要可以参考其他文章。 2、上传资源 不论是上传训练好的模型进行预测&#xff0c;还是训练用的…

泛微开发修炼之旅--33基于ecology实现附件上传接口,提供给外部应用使用

文章链接&#xff1a;33基于ecology实现附件上传接口&#xff0c;提供给外部应用使用

从FasterTransformer源码解读开始了解大模型(2.1)代码通读03

从FasterTransformer源码解读开始了解大模型&#xff08;2.2&#xff09;代码解读03-forward函数 写在前面的话 本篇的内容继续解读forward函数&#xff0c;从650行开始进行解读 零、输出Context_embeddings和context_cum_log_probs的参数和逻辑 从653行开始&#xff0c;会…

Edge浏览器油猴插件的安装与使用

油猴 (又称篡改猴或Tampermonkey) 是最流行的浏览器扩展之一。它允许用户自定义并增强网页的功能。用户脚本是小型 JavaScript 程序&#xff0c;可用于向网页添加新功能或修改现有功能。使用油猴&#xff0c;您可以轻松在任何网站上创建、管理和运行这些用户脚本。 1.插件的安…

spRAG框架学习小结

spRAG是什么 spRAG是一个针对非结构化数据的检索引擎。它特别擅长处理对密集文本的复杂查询&#xff0c;比如财务报告、法律文件和学术论文。有两种关键方法用于提高性能&#xff0c;超越了普通的RAG系统&#xff1a; 自动上下文&#xff08;AutoContext&#xff09;&#xff…

SQLServer Manager Studio扩展开发从入门到弃坑

Visualstudio的已经开发好了&#xff0c;可这个就是不行&#xff0c;直接运行点这些按钮加载失败&#xff0c;而我直接不调试模式&#xff0c;则直接什么都没有&#xff0c;调试 发现是根本没触发逻辑的。 文档资料太少&#xff0c; 我换了几个ssms.exe都不行&#xff0c;18-20…

【电路笔记】-AB类放大器

AB类放大器 文章目录 AB类放大器1、概述2、AB类放大器介绍3、AB类放大器效率4、偏置方法4.1 电压偏置4.2 分压网络4.3 电位器偏置4.4 二极管偏置5、二极管网络和电流源6、AB类放大器的电源分配7、总结1、概述 A类放大器提供非常好的输出线性度,这意味着可以忠实地再现信号,但…

Nacos架构设计

Nacos1.X架构设计 Nacos2.X架构修改

[240707] X-CMD v0.3.14: cb gh fjo zig 模块增强;新增 lsio 和 pixi 模块

目录 X-CMD 发布 v0.3.14✨ advise&#xff1a;Bash 环境下自动补全时&#xff0c;提供命令的描述信息✨ cb:支持下载指定版本的附件资源✨ gh:支持下载指定版本的附件资源✨ fjo:支持下载指定版本的附件资源✨ zig&#xff1a;新增 pm 和 zon 子命令✨ lsio&#xff1a;用于查…

Raylib 坐标系

draftx 符号调整为正数 发现采样坐标系原点0&#xff0c;0 在左上角&#xff0c;正方向 右&#xff0c;下 绘制坐标系 原点0&#xff0c;0 在左下角&#xff0c;正方向 右&#xff0c;上 拖拽可得 #include <raylib.h> // 重整原因&#xff1a;解决新函数放大缩小之下…

华媒舍:8种网站构建推广方法全揭密!

网站构建成为了推广宣传和宣传品牌的关键一环。对于新手&#xff0c;搭建和营销推广网站有可能是一项全新的挑战。下面我们就为大家介绍8种网站搭建和营销推广技巧&#xff0c;帮助你在这些方面取得成功。 1.选择适合自己的网站构建平台选择合适的网站构建平台针对构建一个成功…

阿里云ecs服务器,nginx多域名多项目部署教程,含本地部署教程

nginx多域名部署项目 本地部署线上部署 一、本地部署 第一步&#xff1a; winr 输入drivers 打开hosts文件&#xff0c;编辑 加行 127.0.0.1 自定义域名 … 第二步&#xff1a; 下载 nginx 安装好以后 打开ngin安装目录&#xff0c;选择nginx.conf 打开 #user Administ…

【Transformer】transformer模型结构学习笔记

文章目录 1. transformer架构2. transformer子层解析3. transformer注意力机制4. transformer部分释疑 图1 transformer模型架构 图2 transformer主要模块简介 图3 encoder-decoder示意图N6 图4 encoder-decoder子层示意图 1. transformer架构 encoder-decoder框架是一种处理NL…

ZYNQ-LINUX环境C语言利用Curl库实现HTTP通讯

前言 在Zynq-Linux环境中&#xff0c;需要使用C语言来编写APP时&#xff0c;访问HTTP一般可以使用Curl库来实现&#xff0c;但是在Zynq的SDK中&#xff0c;并没有集成该库&#xff0c;在寻找了很多资料后找到了一种使用很方便的额办法。这篇文章主要记录一下移植Curl的过程。 …

一招解决找不到d3dcompiler43.dll,无法继续执行代码问题

当您的电脑遇到d3dcompiler43.dll缺失问题时&#xff0c;首先需要了解d3dcompiler43.dll文件及其可能导致问题的原因&#xff0c;之后便可以选择合适的解决方案。在此&#xff0c;我们将会为您提供寻找d3dcompiler43.dll文件的多种处理方法。 一、d3dcompiler43.dll文件分析 d…

C++入门7——string类详解

目录 1.什么是string类&#xff1f; 2.string类对象的常见构造 2.1 string(); 2.2 string (const char* s); 2.3 string (const string& str); 2.4 string (const string& str, size_t pos, size_t len npos); 2.5 string (const char* s, size_t n); 2.7 验证…

绝区肆--2024 年AI安全状况

前言 随着人工智能系统变得越来越强大和普及&#xff0c;与之相关的安全问题也越来越多。让我们来看看 2024 年人工智能安全的现状——评估威胁、分析漏洞、审查有前景的防御策略&#xff0c;并推测这一关键领域的未来可能如何。 主要的人工智能安全威胁 人工智能系统和应用程…

Java里的Arrary详解

DK 中提供了一个专门用于操作数组的工具类&#xff0c;即Arrays 类&#xff0c;位于java.util 包中。该类提供了一些列方法来操作数组&#xff0c;如排序、复制、比较、填充等&#xff0c;用户直接调用这些方法即可不需要自己编码实现&#xff0c;降低了开发难度。 java.util.…

Python爬虫系列-让爬虫自己写爬虫(半自动化,代替人工写爬虫)

现在的PC、手机客户端等终端设备大量使用了网页前后端技术&#xff0c;另外主流的网站也会经常会更新&#xff0c;导致以前一个月更新一次爬虫代码&#xff0c;变成了天天需要更新代码&#xff0c;所以自动化爬虫技术在当前就显得特别重要&#xff0c;最近我也是在多次更新某个…