【C++】vector 的模拟实现

📢博客主页:https://blog.csdn.net/2301_779549673
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨

在这里插入图片描述

在这里插入图片描述

文章目录

  • 📢前言
  • 🏳️‍🌈一、vector 模拟实现的基础
  • 🏳️‍🌈二、构造函数与析构函数
  • 🏳️‍🌈三、元素访问与操作函数
  • 🏳️‍🌈四、数据修改函数
  • 🏳️‍🌈五、赋值运算符重载
  • 🏳️‍🌈整体代码
  • 👥总结


📢前言

在 C++ 的编程世界中,vector 是一种极为常用的数据结构。理解其内部工作原理并进行模拟实现,能让我们更深入地掌握 C++ 编程的精髓。本文将带您走进 vector 模拟实现的世界,揭示其背后的神秘面纱,助您提升编程技能。


🏳️‍🌈一、vector 模拟实现的基础

迭代器的理解
vector 的模拟实现中,迭代器起着关键作用。vector 的迭代器本质上是一个原生指针,这使得对元素的访问和操作相对简单。通过指针的移动和解引用,能够方便地实现对 vector 中元素的遍历、读取和修改。但需要注意的是,对于不同的容器,迭代器的实现方式可能会有所不同。比如在链表等非连续存储的容器中,迭代器的实现就会更加复杂,需要考虑节点的连接和遍历逻辑。

私有成员变量的定义及作用
vector 的模拟实现中,定义了三个私有成员变量:startfinishend_of_storagestart 指针指向 vector 的第一个元素,finish 指针指向最后一个有效元素的下一个位置,end_of_storage 指针指向整个存储空间的末尾。

这三个指针共同协作,管理着 vector 的存储空间和元素范围。通过对它们的操作和维护,实现了 vector 的动态增长、元素插入、删除、容量调整等功能。例如,在扩容操作中,需要根据 end_of_storage 和 finish 的关系来判断是否需要重新分配更大的空间,并更新这三个指针的值以保证 vector 的正常运作。

	private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;

vector的定义

在这里插入图片描述
在这里插入图片描述

🏳️‍🌈二、构造函数与析构函数

无参构造函数
无参构造函数将三个私有成员变量 startfinishend_of_storage 初始化为 nullptr,实现如下:

vector() {_start = nullptr;_finish = nullptr;_end_of_storage = nullptr;
}

带参数的构造函数(包括 size_t 和 int 类型)
对于带参数的构造函数,当参数类型为 size_t 时,会先为 vector 分配指定数量的空间,并为每个元素进行初始化。代码如下:

vector(size_t n, const T& val = T()) {_start = new T[n];_finish = _start;_end_of_storage = _start + n;for (size_t i = 0; i < n; ++i) {*_finish++ = val;}
}

区间构造函数
区间构造函数接收两个迭代器 firstlast,通过循环将区间内的元素插入到 vector 中。代码如下:

template <class InputIterator>
vector(InputIterator first, InputIterator last) {while (first!= last) {push_back(*first);++first;}
}

拷贝构造函数
拷贝构造函数用于创建一个新的 vector 对象,其内容与原对象相同。传统写法如下:

vector(const vector<T>& v) {_start = new T[v.size()];for (size_t i = 0; i < v.size(); ++i) {_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();
}

析构函数
析构函数用于释放 vector 所占用的资源,当 _start 不为空时,释放动态分配的内存,并将三个指针置为 nullptr。代码如下:

~vector() {if (_start) {delete[] _start;_start = _finish = _end_of_storage = nullptr;}
}

🏳️‍🌈三、元素访问与操作函数

获取迭代器的函数
begin 函数返回一个指向 vector 起始位置的迭代器,代码实现为 iterator begin() { return _start; }
end 函数返回一个指向 vector 结束位置(即最后一个元素的下一个位置)的迭代器,实现方式为iterator end() { return _finish; }
cbegin 函数返回一个常量迭代器,指向 vector 的起始位置,代码为 const_iterator cbegin() const { return _start; }
cend 函数返回一个常量迭代器,指向 vector 的结束位置,即 onst_iterator cend() const { return _finish; }

元素访问函数
operator[] 函数用于访问 vector 中的元素。

//它实现了两种版本,一种是 const 版本,用于只读访问,代码为
const T& operator[](size_t pos) const 
{ assert(pos < size()); return _start[pos]; 
}//另一种是非 const 版本,允许通过索引修改元素的值,实现为 
T& operator[](size_t pos) 
{ assert(pos < size()); return _start[pos];
} 

获取容量和大小的函数
size 函数用于获取 vector 中元素的个数,通过计算 _finish - _start 得出,
capacity 函数用于获取 vector 的容量大小,即通过计算 _end_of_storage - _start 得到,
empty 函数用于判断 vector 是否为空,通过比较 _start_finish 是否相等来确定,

size_t size() const
{return _finish - _start;
}size_t capacity() const
{return _end_of_storage - _start;
}bool empty()
{return (_finish == _start);
}

size_t size() const 中,const 的作用主要有以下几点:

  1. 表明该函数不会修改类的成员变量:这意味着在函数内部,不能对类的非静态成员变量进行修改操作,保证了函数的只读性质。这对于保证类的封装性和数据的一致性非常重要。
  2. 允许常量对象调用该函数:如果一个对象被定义为常量,即 const 类型,那么它只能调用 const 成员函数。如果 size 函数没有 const 修饰,那么常量对象就无法调用这个函数来获取元素数量。

例如,假设有一个常量的 vector 对象 const vector v; ,如果 size 函数不是 const 的,就会导致编译错误,而有了 const 修饰,就可以正常通过 v.size() 来获取元素数量。

  1. 增强代码的可读性和可维护性:当看到一个函数被标记为 const 时,开发者可以立即知道这个函数不会修改对象的状态,有助于更好地理解代码的行为。

🏳️‍🌈四、数据修改函数

扩容函数(reserve)
reserve函数用于预分配vector的存储空间。
需要注意的是,reserve分配的内存未进行初始化,且访问未初始化的内存可能导致程序崩溃。
总之,在使用这些数据修改函数时,要特别注意迭代器失效的问题,及时更新迭代器以保证程序的正确性。

		void reserve(size_t n){if (n > capacity()){size_t old_size = size();T* tmp = new T[n];//memcpy(tmp, _start, size() * sizeof(T));// T不一定是内置类型,可能会造成乱码,得深拷贝for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finish = _start + old_size;_end_of_storage = _start + n;}}

尾插函数(push_back)
push_back函数用于在vector的末尾添加元素。
当vector的剩余空间不足时,可能会进行内存的重新分配和数据的拷贝。
在一些情况下,这可能导致之前获取的迭代器失效。

		void push_back(const T& x){if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;}

改变数组长度函数(resize)
resize函数用于改变vector的有效长度。
如果resize后的长度小于当前长度,会删除多余的元素。
如果大于当前长度,会插入新的元素并进行初始化。
使用resize时,同样要关注迭代器的有效性。

		void resize(size_t n, T val = T()){if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}}

插入函数(insert)
insert函数用于在vector的指定位置插入元素。它有多种用法:

  • 可以在指定位置插入单个元素,返回指向插入元素的迭代器。
  • 能在指定位置插入指定数量的相同元素。
  • 还可以插入一个区间内的元素。
    在使用insert时需要注意迭代器失效的问题。当插入元素导致vector重新分配内存时,之前获取的迭代器可能会失效。解决方法是在插入操作后重新获取迭代器。
		iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - begin();// 防止扩容后导致相对位置发生变化reserve(capacity() == 0 ? 4 : capacity() * 2);pos = begin() + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;}

删除函数(erase、pop_back)
erase函数可以通过迭代器删除指定元素或指定位置的元素。
使用时要注意迭代器的正确操作,避免出现野指针导致程序错误。

pop_back函数用于删除vector的最后一个元素。
当进行删除操作时,如果导致vector内存重新分配,相关迭代器也可能失效。

		void erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);iterator it = pos + 1;while (it != end()){*(it - 1) = *it;it++;}--_finish;}void pop_back() {assert(!empty());--_finish;}

🏳️‍🌈五、赋值运算符重载

在 vector 的模拟实现中,赋值运算符重载 operator= 起着重要的作用。其实现方式通常是通过复制源 vector 的元素来更新目标 vector 的内容。
常见的实现方式是创建一个临时的 vector 对象,将源 vector 的元素复制到这个临时对象中,然后通过交换操作来更新目标 vector 的状态。这样可以避免直接操作目标 vector 可能导致的内存管理问题。
赋值运算符重载的作用主要有以下几点:

  1. 方便对象之间的赋值操作,使得 vector 对象可以像基本数据类型一样进行赋值,提高了代码的简洁性和可读性。
  2. 支持不同 vector 对象之间的数据传递和更新,使得代码逻辑更加清晰和易于理解。
  3. 确保在赋值过程中正确处理内存管理,避免内存泄漏和数据错误。
		vector<T>& operator=(const vector<T>& v){if (this != &v){clear();reverse(v.size());for (auto& e : v){push_back(e);}}return *this;}

🏳️‍🌈整体代码

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
#include<assert.h>
#include<list>
using namespace std;// 模板的原理是将我们要做的事交给编译器去// vector<vector<int>> vv(10, v);   // 有点像二维数组// vector<int> v(5, 1);namespace bit
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;// C++11 前置生成默认构造vector() = default;// 拷贝构造//vector(const vector<T>& v)vector(const vector& v){reserve(v.size());for (auto& e : v){push_back(e);}}// 重载vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}void clear(){_finish = _start;}// v3 =v1vector<T>& operator=(const vector<T>& v){if (this != &v){clear();reverse(v.size());for (auto& e : v){push_back(e);}}return *this;}// 模板// 任意类型迭代器初始化,要求类型是匹配的template <class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}iterator begin(){return _start;}iterator end(){return _finish;}// 如果第二个const没有,就会导致,对于 const 对象,将无法调用这个 begin 函数。因为 const 对象只能调用 const 成员函数。const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}// 扩容void reserve(size_t n){if (n > capacity()){size_t old_size = size();T* tmp = new T[n];//memcpy(tmp, _start, size() * sizeof(T));// T不一定是内置类型,可能会造成乱码,得深拷贝for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finish = _start + old_size;_end_of_storage = _start + n;}}size_t size() const{return _finish - _start;}size_t capacity() const{return _end_of_storage - _start;}bool empty(){return (_finish == _start);}// 尾插void push_back(const T& x){if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;}void pop_back() {assert(!empty());--_finish;}iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - begin();// 防止扩容后导致相对位置发生变化reserve(capacity() == 0 ? 4 : capacity() * 2);pos = begin() + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;}// 删除指定位置void erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);iterator it = pos + 1;while (it != end()){*(it - 1) = *it;it++;}--_finish;}void resize(size_t n, T val = T()){if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}}T operator[](size_t i){assert(i < size());return _start[i];}//void swap(vector<T>& v) void swap(vector& v)// 类里面加不加<T>都行{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}private:iterator  _start = nullptr;iterator  _finish = nullptr;iterator _end_of_storage = nullptr;};// 添加模板template<class T>void print_vector(const vector<T>& v){// 必须加typename// 在没有实例化的内模板(没有int等)中取东西,编译器不能区分这个const_iterator是类型还是静态成员变量(仅是初步检查)typename vector<T>::const_iterator it = v.begin();while (it != v.end()){cout << *it << "	";++it;}cout << endl;for (auto e : v){cout << e << "	";}cout << endl;}template<class Container>void print_container(const Container& v){/*auto it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;*/for (auto e : v){cout << e << " ";}cout << endl;}void test_vector1(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(4);v.push_back(5);v.insert(v.begin() + 2, 9);for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;for(auto e : v){cout << e << " ";}cout << endl;cout << endl;print_vector(v);cout << endl;vector<double> vd;vd.push_back(1.1);vd.push_back(2.2);vd.push_back(3.3);vd.push_back(4.4);vd.push_back(5.5);vd.insert(vd.begin() + 2, 9);print_vector(vd);}void test_vector2(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(4);v.push_back(5);print_container(v);// 删除所有的偶数auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);else++it;}print_container(v);}void test_vector3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(4);v1.push_back(5);v1.resize(10, 9);v1.resize(20);print_container(v1);vector<int> v2(v1);print_container(v2);vector<int> v3(v1.begin(), v1.begin() + 3);print_container(v3);vector<string> v4(10, "11111");print_container(v4);v4.push_back("22222");v4.push_back("22222");v4.push_back("22222");v4.push_back("22222");v4.push_back("22222");print_container(v4);}}

👥总结

vector模拟实现的要点包括:

  1. 迭代器的巧妙运用,通过原生指针实现简单高效的元素访问和操作。
  2. 合理定义和管理私有成员变量start、finish和end_of_storage,实现对存储空间和元素范围的精确控制。
  3. 构造函数涵盖了多种情况,满足不同的初始化需求。
  4. 丰富的元素访问和操作函数,如insert、erase、push_back等,实现了对元素的灵活处理。
  5. 准确获取容量、大小等信息,以及通过reserve、resize等函数进行空间管理。
  6. 赋值运算符重载确保了对象赋值的便捷和安全。

优化方向

  1. 内存管理优化:可以考虑更精细的内存分配策略,减少不必要的内存浪费和频繁的重新分配。
  2. 性能提升:例如在插入和删除操作中,采用更高效的数据移动方式。
  3. 异常处理完善:增强对各种异常情况的处理,提高程序的健壮性。

拓展可能性

  1. 支持更多的模板参数:如增加内存分配器的选择,适应不同的场景需求。
  2. 与其他数据结构的结合:例如与链表或树结构结合,形成更复杂但功能更强大的数据结构。
  3. 多线程安全:使vector在多线程环境下能够安全地进行操作。
  4. 自定义比较器:支持用户自定义元素的比较规则,丰富排序和查找等操作。

本篇博文对 vector的模拟实现 做了一个较为详细的介绍,不知道对你有没有帮助呢

觉得博主写得还不错的三连支持下吧!会继续努力的~

请添加图片描述

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

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

相关文章

02_快速启动 Demo 创建 Electron 项目、electron-forge 搭建一个 electron 项目、手动创建electron项目

快速启动 Demo 创建 Electron 项目 一、克隆一个仓库、快速启动一个项目二、electron-forge 搭建一个 electron 项目三、手动搭建一个 electron 项目四、开发工具中配置 Eslint 一、克隆一个仓库、快速启动一个项目 要使用 git 的话首先电脑上面需要安装 git //克隆示例项目的…

Qt3D给圆环等立体图形添加纹理图片

添加纹理图片&#xff0c;首先需要自己找一个纹理图&#xff0c;当然了&#xff0c;随便什么图片都行。 创建3D图形的主要步骤查看另一篇文章。 这里主要代码如下&#xff1a; 使用QTextureLoader加载图片&#xff0c;图片路径需为qrc:/的路径。 auto *planeTransform1 ne…

嵌入式学习day13(C高级Linux命令)

一丶进程管理命令 1.grep 功能&#xff1a;从文件中查找字符串 格式&#xff1a;grep "要查找的字符串" 文件名 精确查找&#xff1a;grep "\<要查找的字符串\>" 文件名 结合ps以及管道&#xff1a;ps -ef | grep a.out: 从进程信息中查找带…

10个理由告诉你,为什么鸿蒙是下一个职业风口!

在当今科技飞速发展的时代&#xff0c;新的技术和趋势不断涌现&#xff0c;为人们带来了前所未有的机遇和挑战。鸿蒙操作系统作为我国自主研发的创新成果&#xff0c;正逐渐成为科技领域的焦点&#xff0c;被认为是下一个职业风口。 10个理由告诉你&#xff0c;为什么鸿蒙是下一…

【海贼王航海日志:前端技术探索】CSS你了解多少?(二)

目录 1 -> 字体属性 1.1 -> 设置字体 1.2 -> 字体大小 1.3 -> 字体粗细 1.4 -> 文字样式 2 -> 文本属性 2.1 -> 文本颜色 2.1.1 -> 认识RGB 2.1.2 -> 设置文本颜色 2.2 -> 文本对齐 2.3 -> 文本装饰 2.4 -> 文本缩进 2.5 -&g…

vue的nextTick是下一次事件循环吗

如题&#xff0c;nextTick的回调是在下一次事件循环被执行的吗&#xff1f; 是不是下一次事件循环取决于nextTick的实现&#xff0c;如果是用的微任务&#xff0c;那么就是本次事件循环&#xff1b;否则如果用的是宏任务&#xff0c;那么就是下一次事件循环。 我们看下Vue3中…

【Canvas与艺术】黄色立体感放射光芒五角星

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>黄色立体感放射光芒五角星</title><style type"text/c…

Html详解——Vue基础

HTML是什么&#xff1f; 超文本标记语言&#xff08;英语&#xff1a;HyperText Markup Language&#xff0c;简称&#xff1a;HTML&#xff09;是一种用来结构化 Web 网页及其内容的标记语言。网页内容可以是&#xff1a;一组段落、一个重点信息列表、也可以含有图片和数据表…

[Vue]Vue3从入门到精通-综合案例分析

一.Vue是什么&#xff1a; 概念&#xff1a;Vue是一个用于构建用户界面的渐进式的框架 以下的内容是自里向外的 声明式渲染(Vuejs核心包)组件系统(Vuejs核心包)客户端路由VueRouter大规模状态管理Vuex构建工具Webpack/Vite Vue的两种使用方式&#xff1a; Vue核心包开发-&…

DSL domain specific language of Kola

How we design Kola - ApiHugKola background, Kola a consumer driver tester frameworkhttps://apihug.com/zhCN-docs/kola/003_dsl_contract Concept 在 Kola 定位中 Kola 是什么, 是致力于提供一个让相关各方都能够理解共同创造的测试框架和工具。 同时 Kola 是建立于业界…

node中使用http创建web服务器

1.案例代码 // 1.导入http模块 const http require(http)// 2.创建web服务器实例 const server http.createServer()// 3.为服务器实例绑定request事件&#xff0c;监听客户的请求 server.on(request,function(req,res){console.log(欢迎来到服务器);// req.url是客户端请求…

Kubernets(k8s) 网络原理二:Pod访问外网

上一篇文章中&#xff0c;我们介绍了pod与宿主机通信&#xff0c;并且通过network namespace模拟了通信过程。回顾整个流程&#xff0c;无非就涉及到两个东西&#xff0c;通信设备和路由规则。 本文要讲的&#xff0c;也离不开这两个东西&#xff0c;只不过需要对容器IP进行额…

学习c语言第24天(练习)

编程题 第一题 最大公约数最小公倍数求和 //求最大公约数和最小公倍数之和 //暴力求解 //int main() //{ // int n 0; // int m 0; // while (scanf("%d %d", &n, &m)2) // { // int min n < m ? n : m; // int max n > m ? n : m; //…

Stable Diffusion 使用详解(7)---AI 摄影

目录 背景 底模的选择 例子 majicMix GirlFriendMix&#xff08; Lora&#xff09; 对比效果 LEOSAMs MoonFilm ADetailer 使用 说明 例子 问题 处理方式 效果 背景 魔法师使用魔法作的画有时候太过完美&#xff0c;以至于有点脱离真实摄影的感觉&#xff0c;我们…

【电控笔记z14z16】增加霍尔元件分辨率

霍尔传感器用的不多?实际增量编码器更好 z14 假设60度内速度不变 z16(更简单的方法)BLDC

【机器学习】BP神经网络正向计算

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 BP神经网络正向计算1. 引言2. BP神经网络结构回顾3. 正向计算的基本原理4. 数学…

7.3.1.算法设计与分析-总结及真题讲解

总结 分治法特征&#xff1a;把一个问题拆分成多个小规模的相同子问题&#xff0c;一般可用递归解决。 经典问题&#xff1a;斐波那契数列、归并排序、快速排序、矩阵乘法、二分搜索、大整数乘法、汉诺塔 回溯法特征&#xff1a;系统的搜索一个问题的所有解或任一解。 经典问题…

ctfhub文件上传

⽆验证 上传⼀句话⽊⻢&#xff0c;发现上传成功 1.php ⼀句话⽊⻢内容&#xff1a; <?php eval($_POST[cmd]);?> 上传⼀句话⽊⻢&#xff0c;发现上传成功 http://challenge-8b27d18368ecc25c.sandbox.ctfhub.com:10800/upload/1.ph p 前端验证 开启题⽬ 上传⼀个…

[Modbus] Modbus协议开发-基本概念(一)

历史 ModBus官网是Modicon&#xff08;Modicon早年已被施耐德收购&#xff09;公司为其PLC通讯而开发的一种通讯协议。 概述 通过Modbus协议&#xff0c;控制器之间、或控制器经由网络&#xff08;如以太网&#xff09;可以和其它设备之间进行通信。 优点 免费、好用、成熟…

DIRB:一款强大的Web目录扫描工具使用指南

网安学习交流 DIRB是一款广泛使用的开源Web内容扫描工具&#xff0c;它专注于发现Web服务器上存在的目录和文件。对于安全研究员、渗透测试人员以及Web开发者来说&#xff0c;DIRB是一个不可或缺的工具&#xff0c;它能帮助他们识别潜在的入口点&#xff0c;从而进一步评估目标…