【STL】vector介绍(附部分接口模拟实现)

news2025/3/30 15:20:48

文章目录

  • 1.介绍
  • 2.使用
    • 2.1 vector的构造
    • 2.2 vector空间相关接口
      • 2.2.1 size()
      • 2.2.2 capacity()
      • 2.2.3 empty()
      • 2.2.4 resize()
      • 2.2.5 reserve()
    • 2.3 vector的增删查改
      • 2.3.1 push_back()
      • 2.3.2 insert()
      • 2.3.3 pop_back()
      • 2.3.4 erase()
      • 2.3.5 swap()
      • 2.3.6 operator[]
      • 注:关于查找find()
    • 2.4 其它
      • 2.4.1 at()
      • 2.4.2 front()和back()
  • 3.部分接口的模拟实现

1.介绍

​ vector容器是一种大小可变的序列容器,可以看作一个动态数组,其采用连续的存储空间来存储元素,允许动态插入和删除元素,可以自动管理内存空间,当需要的内存空间大小大于当前内存空间大小时,会自动分配一个更大的新的数组,将全部元素转移过来,其也具备可迭代性。

2.使用

​ 同样,在使用上,这里只介绍一些经常使用的接口函数。

2.1 vector的构造

1.定义

构造函数声明说明
vector()无参构造
vector(size_type n,const value_type& val = value_type())构造并用n个val初始化
vector(const vector& x)拷贝构造
vector(InputIterator first, InputIterator last)使用迭代器进行初始化构造

2.使用

#include <iostream>
#include <vector>//包含头文件

using namespace std;

template<typename T>
void PrintVector(vector<T>& v)
{
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

void test1()
{
	//vector的构造 <>中的类型可以修改
	vector<int> v1;//无参构造
	vector<int> v2(10, 2);//用10个2初始化构造
	vector<int> v3(v2);//用v2拷贝构造
	vector<int> v4(v2.begin() + 1, v2.end() - 1);//迭代器构造从v2的begin() + 1到end() - 1位置

	PrintVector(v1);
	PrintVector(v2);
	PrintVector(v3);
	PrintVector(v4);
}

int main()
{
	test1();
	return 0;
}

结果如下:

在这里插入图片描述

2.2 vector空间相关接口

2.2.1 size()

1.声明及作用:

声明作用
size_type size() const;获取有效数据个数

2.使用:

void test2()
{
	vector<int> nums({ 1,2,3,4,5,6 });
	size_t nums_len = nums.size();
	cout << nums_len << endl;//6
}

int main()
{
	test2();
	return 0;
}

2.2.2 capacity()

1.声明及作用:

声明作用
size_type capacity() const;获取空间容量大小

2.使用:

void test3()
{
	vector<int> nums;
	size_t capacity = nums.capacity();//使用
	for (size_t i = 1; i <= 100; i++)
	{
		nums.push_back(1);//尾插100个1
		size_t new_capacity = nums.capacity();//使用
		//如果空间容量大小发生变化,打印新的大小
		if (new_capacity != capacity)
		{
			capacity = new_capacity;
			cout << capacity << endl;
		}
	}
}
int main()
{
	test3();
	return 0;
}

输出结果为:
1
2
3
4
6
9
13
19
28
42
63
94
141

​ 这里我们通过尾插100个1顺便观察VS下vector的扩容规律:其capacity是按1.5倍增长的,注:在不同的环境下vector的增容不一定相同,比如:在Linux g++下其可能是按2倍扩容。

2.2.3 empty()

1.声明及作用:

声明作用
bool empty() const;判断该vector是否为空

2.使用:

void test4()
{
	vector<int> v1;
	if (v1.empty())
	{
		cout << "v1是空的" << endl;
	}
	else
	{
		cout << "v1是非空的" << endl;
	}

	vector<int> v2{1,2,3,4};
	if (v2.empty())
	{
		cout << "v2是空的" << endl;
	}
	else
	{
		cout << "v2是非空的" << endl;
	}
}
int main()
{
	test4();
	return 0;
}
输出:
v1是空的
v2是非空的

2.2.4 resize()

1.声明及作用:

声明作用
void resize (size_type n, value_type val = value_type());指定vector有效size大小为n,当n大于当前 vector的大小时,resize()会在vector末尾添加新元素val,不填val则为默认值。当n小于当前vector的大小时,resize()会移除vector末尾的元素,使vector的大小变为n。

2.使用:

template<typename T>
void PrintVector(vector<T>& v)
{
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

void test5()
{
	vector<int> v;
	v.resize(10, 1);//n=10>当前size,在末尾添加10个val = 1;
	PrintVector(v);//打印v

	v.resize(20);//n=20>当前size,在末尾添加10个val,默认为0;
	PrintVector(v);

	v.resize(5);//n=5<当前size,从末尾移除元素直至size=5
	PrintVector(v);
}
int main()
{
	test5();
	return 0;
}

结果如下:

在这里插入图片描述

2.2.5 reserve()

1.声明及作用:

声明作用
void reserve (size_type n);预先分配至少能容纳数量为n的内存空间,它会增加vector的capacity但不会改变有效元素的数量size

2.使用:

void test6()
{
	vector<int> v;
	cout << "before reserve'size:" << v.size() << endl;
	cout << "before reserve'capacity:" << v.capacity()<< endl;
	v.reserve(20);
	cout << "after reserve'size:" << v.size() << endl;//不改变size
	cout << "after reserve'capacity:" << v.capacity() << endl;//增加capacity
}
int main()
{
	test6();
	return 0;
}

结果如下:

在这里插入图片描述

​ 当我们知道需要大概多少的空间大小时,我们可以通过reserve提前开辟空间以缓解vector增容的代价。

2.3 vector的增删查改

2.3.1 push_back()

1.声明及作用

声明作用
void push_back (const value_type& val);尾插val

2.使用:

template<typename T>
void PrintVector(vector<T>& v)
{
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

void test7()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	PrintVector(v);//1 2 3 4 5
}
int main()
{
	test6();
	return 0;
}

2.3.2 insert()

1.声明及作用

声明作用
iterator insert (const_iterator position, const value_type& val);在position位置的值前插入val
iterator insert (const_iterator position, size_type n, const value_type& val);在position位置的值前插入n个val

2.使用:

template<typename T>
void PrintVector(vector<T>& v)
{
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}
void test8()
{
	vector<int> v;
	v.insert(v.begin(), 1);//在起始位置前插入1(相当于头插)
	PrintVector(v);//1
	v.insert(v.end(), 2);//在结束位置前插入1(相当于尾插)
	PrintVector(v);//1 2
	v.insert(v.begin() + 1, 5, 3);//在begin()+1位置前插入5个3
	PrintVector(v);//1 3 3 3 3 3 2
}
int main()
{
	test8();
	return 0;
}

2.3.3 pop_back()

1.声明及作用

声明作用
void pop_back();尾删

2.使用

template<typename T>
void PrintVector(vector<T>& v)
{
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}
void test9()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	PrintVector(v);//1 2 3 4 5

	v.pop_back();//尾删
	PrintVector(v);//1 2 3 4
	v.pop_back();
	PrintVector(v);//1 2 3
	v.pop_back();
	PrintVector(v);//1 2
	v.pop_back();
	PrintVector(v);//1
	v.pop_back();
	PrintVector(v);//
}
int main()
{
	test9();
	return 0;
}

2.3.4 erase()

1.声明及作用

声明作用
iterator erase (const_iterator position);删除position位置的值
iterator erase (const_iterator first, const_iterator last);从first位置开始删到last位置前(左闭右开)

2.使用

void test10()
{
	vector<int> v;
	for (int i = 1; i <= 10; i++)
	{
		v.push_back(i);
	}
	PrintVector(v);//1 2 3 4 5 6 7 8 9 10

	v.erase(v.begin() + 5);//删除begin()+5位置的值(6)
	PrintVector(v);//1 2 3 4 5 7 8 9 10

	v.erase(v.begin() + 1, v.end() - 1);
	PrintVector(v);//1 10
}
int main()
{
	test10();
	return 0;
}

2.3.5 swap()

1.声明及作用

声明作用
void swap (vector& x);交换两个vector的数据空间

2.使用

template<typename T>
void PrintVector(vector<T>& v)
{
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}
void test11()
{
	vector<int> v1(5, 1);
	vector<int> v2(10, 2);
	cout << "before swap v1:";
	PrintVector(v1);
	cout << "before swap v2:";
	PrintVector(v2);

	v1.swap(v2);//交换v1和v2
	cout << "after swap v1:";
	PrintVector(v1);
	cout << "after swap v2:";
	PrintVector(v2);
}
int main()
{
	test11();
	return 0;
}

结果如下:

在这里插入图片描述

2.3.6 operator[]

1.声明及作用

声明作用
reference operator[] (size_type n);用于非const对象,返回vector中索引为n的值,可进行读取和修改
const_reference operator[] (size_type n) const;用于const对象,返回vector中索引为n的值,只能进行读取

2.使用

void test12()
{
    //非const对象
	vector<int> v1;
	for (int i = 1; i <= 10; i++)
	{
		v1.push_back(i);
	}
	for (int i = 0; i < 10; i++)
	{
		cout << v1[i] << " ";//读取索引为i的值
	}
	cout << endl;
	for (int i = 0; i < 10; i++)
	{
		++v1[i];//修改索引为i的值
	}
	for (int i = 0; i < 10; i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;
    
    //const对象
	const vector<int> v2(10, 2);
	for (int i = 0; i < 10; i++)
	{
		cout << v2[i] << " ";//读取索引为i的值
	}
	cout << endl;
	//for (int i = 0; i < 10; i++)
	//{
	//	++v2[i];//不允许修改
	//}
}
int main()
{
	test12();
	return 0;
}

结果如下:

在这里插入图片描述

注:关于查找find()

​ 在vector中没有单独添加find()的接口函数,可以使用算法板块的查找操作,这里举个例子:

void test13()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	v.push_back(6);
	v.push_back(7);
	PrintVector(v);//1 2 3 4 5 6 7
	v.insert(find(v.begin(),v.end(),4), 5, 3);//通过find从v的begin到end区间找到4,并返回4的位置,在该位置前插入5个3
	PrintVector(v);//1 2 3 3 3 3 3 3 4 5 6 7
}
int main()
{
	test13();
	return 0;
}

2.4 其它

2.4.1 at()

1.作用:返回索引值位置的值,对于非const对象可以进行读取和修改,对于const对象只能读取

2.使用:

void test14()
{
	vector<int> v1{1,2,3,4,5};
	cout << v1.at(0) << endl;//1
	++v1.at(0);
	cout << v1.at(0) << endl;//2

	const vector<int> v2{1,2,3,4,5};
	cout << v2.at(2) << endl;//3
	//++v2.at(2);   const对象  不允许修改
}
int main()
{
	test14();
	return 0;
}

2.4.2 front()和back()

1.作用:front()返回容器中的首元素,back()返回容器中的末尾元素

2.使用:

void test15()
{
	vector<int> v{ 1,2,3,4,5,6 };
	cout << "front():" << v.front() << endl;//front():1
	cout << "back():" << v.back() << endl;//back():6
}

int main()
{
	test15();
	return 0;
}

3.部分接口的模拟实现

​ 这里仅给出代码,不做详细介绍,有任何问题欢迎提出讨论。

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;

namespace myVector
{
    template<class T>
    class vector
    {
    public:
        // Vector的迭代器是一个原生指针
        typedef T* iterator;
        typedef const T* const_iterator;

        // construct and destroy
        vector()
        {}
        /*vector(size_t n, const T& value = T())
        {
            resize(n, value);
        }*/
        /*vector(int n, const T& val = T())
        {
            resize(n, val);
        }*/
        vector(int n, const T& value = T())
        {
            assert(n >= 0);
            reserve(n);
            for (int i = 0; i < n; i++)
            {
                _start[i] = value;
            }
            _finish = _start + n;
        }
        vector(size_t n, const T& value = T())
        {
            reserve(n);
            for (int i = 0; i < n; i++)
            {
                _start[i] = value;
            }
            _finish = _start + n;
        }

        vector(const vector<T>& v)
        {
            reserve(v.capacity());
            for (const auto& e : v)
            {
                push_back(e);
            }
        }

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

        /*vector(const vector<T>& v)
        {
            _start = new T[v.capacity()];
            memcpy(_start, v._start, v.size()* sizeof(T));
            _finish = _start + v.size();
            _endofstorage = _start + v.capacity();
        }*/
        
        /*vector<T>& operator=(vector<T> v)
        {
            swap(v);
            return *this;
        }*/

        vector<T>& operator=(vector<T> v)
        {
            T* tmp = new T[v.size()];
            if (v._start)
            {
                for (int i = 0; i < v.size(); i++)
                {
                    tmp[i] = v[i];
                }
            }
            _start = tmp;
            _finish = _start + v.size();
            _endOfStorage = _start + v.capacity();

            return *this;
        }
        ~vector()
        {
            if (_start)
            {
                delete[] _start;
                _start = nullptr;
                _finish = nullptr;
                _endOfStorage = nullptr;
            }
        }
        iterator begin()
        {
            return _start;
        }
        iterator end()
        {
            return _finish;
        }
        const_iterator begin() const
        {
            return _start;
        }
        const_iterator end() const
        {
            return _finish;
        }
        // capacity
        size_t size() const
        {
            return _finish - _start;
        }
        size_t capacity() const
        {
            return _endOfStorage - _start;
        }
        void reserve(size_t n)
        {
            if (n > capacity())
            {
                size_t old = size();
                T* tmp = new T[n];
                if (_start)
                {
                    for (size_t i = 0; i < old; i++)
                    {
                        tmp[i] = _start[i];
                    }
                }
                delete[] _start;

                _start = tmp;
                _finish = _start + old;
                _endOfStorage = _start + n;
            }
        }
        void resize(size_t n, const T& value = T())
        {
            if (n > capacity())
            {
                reserve(n);
                while (_finish < _start + n)
                {
                    *_finish = value;
                    ++_finish;
                }
            }
            else
            {
                _finish = _start + n;
            }
        }
  
        T& operator[](size_t pos)
        {
            return _start[pos];
        }
        const T& operator[](size_t pos)const
        {
            return _start[pos];
        }
       
        void push_back(const T& x)
        {
            if (_finish == _endOfStorage)
            {
                size_t new_capacity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(new_capacity);
            }
            *_finish = x;
            ++_finish;
        }
      
        void pop_back()
        {
            assert(size() > 0);
            --_finish;
        }
        void swap(vector<T>& v)
        {
            std::swap(_start, v._start);
            std::swap(_finish, v._finish);
            std::swap(_endOfStorage, v._endOfStorage);
        }
        iterator insert(iterator pos, const T& x)
        {
            assert(pos >= _start && pos <= _finish);
            if (_finish == _endOfStorage)
            {
                size_t len = pos - _start;
                size_t new_capacity = capacity() == 0 ? 4 : capacity() * 2;
                reserve(new_capacity);
                pos = _start + len;
            }
            iterator end = _finish - 1;
            while (end >= pos)
            {
                *(end + 1) = *end;
                --end;
            }

            *pos = x;
            ++_finish;

            return pos;
        }
        iterator erase(iterator pos)
        {
            assert(pos >= _start && pos <= _finish);
            iterator it = pos + 1;
            while (it < _finish)
            {
                *(it - 1) = *it;
                ++it;
            }
            --_finish;

            return pos;
        }


    private:
        iterator _start = nullptr; //指向数据块的开始
        iterator _finish = nullptr; //指向有效数据的尾
        iterator _endOfStorage = nullptr; //指向存储容量的尾
    };
    void print_vector(const vector<int>& v)
    {
        for (auto e : v)
        {
            cout << e << " ";
        }
        cout << endl;
    }
}

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

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

相关文章

一周掌握Flutter开发--8. 调试与性能优化(上)

文章目录 8. 调试与性能优化核心技能8.1 使用 Flutter DevTools 分析性能8.2 检查 Widget 重绘&#xff08;debugPaintSizeEnabled&#xff09;8.3 解决 ListView 卡顿&#xff08;ListView.builder itemExtent&#xff09; 其他性能优化技巧8.4 减少 build 方法的调用8.5 使用…

游戏引擎学习第182天

回顾和今天的计划 昨天的进展令人惊喜&#xff0c;原本的调试系统已经被一个新的系统完全替换&#xff0c;新系统不仅能完成原有的所有功能&#xff0c;还能捕获完整的调试信息&#xff0c;包括时间戳等关键数据。这次的替换非常顺利&#xff0c;效果很好。 今天的重点是在此基…

C语言_数据结构_二叉树

【本节目标】 树的概念及结构 二叉树的概念及结构 二叉树的顺序结构及实现 二叉树的链式结构及实现 1. 树的概念及结构 1.1 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为…

Compare全目录文件比较内容(项目中用到过)

第一步&#xff1a;找到“会话”——“会话设置” 会话设置弹框信息 第二步&#xff1a;选择“比较”tab标签 比较内容&#xff1a;选中二进制比较 第三步&#xff1a;选中所有文件 第四步&#xff1a;右键选中“比较内容” 第五步&#xff1a;选中“基于规则的比较”

3.26[a]paracompute homework

5555 负载不平衡指多个线程的计算量差异显著&#xff0c;导致部分线程空转或等待&#xff0c;降低并行效率。其核心矛盾在于任务划分的静态性与计算动态性不匹配&#xff0c;尤其在处理不规则数据或动态任务时尤为突出。以稀疏矩阵的向量乘法为例&#xff0c;假设其非零元素分…

视觉大模型CLIP论文精读

论文&#xff1a;Learning Transferable Visual Models From Natural Language Supervision 代码&#xff1a;https://github.com/openai/CLIP 摘要 最先进的计算机视觉系统是针对预测一组固定的、预先确定的对象类别进行训练的。这种受限的监督形式限制了它们的通用性和可用…

链表的创建:头插法与尾插法详解(数据结构)

C 链表的创建&#xff1a;头插法与尾插法详解 链表&#xff08;Linked List&#xff09;是一种重要的数据结构&#xff0c;适用于插入和删除操作频繁的场景。本文介绍 两种常见的链表构建方法&#xff1a; 尾插法&#xff08;Append / Tail Insertion&#xff09;&#xff1a;…

深入解析 Java 类加载机制及双亲委派模型

&#x1f50d; Java的类加载机制是确保应用程序正确运行的基础&#xff0c;特别是双亲委派模型&#xff0c;它通过父类加载器逐层加载类&#xff0c;避免冲突和重复加载。但在某些特殊场景下&#xff0c;破坏双亲委派模型会带来意想不到的效果。本文将深入解析Java类加载机制、…

MySQL数据库精研之旅第四期:解锁库操作高阶技能

专栏&#xff1a;MySQL数据库成长记 个人主页&#xff1a;手握风云 目录 一、查看所有表 1.1. 语法 二、创建表 2.1. 语法 2.2. 示例 2.3. 表在磁盘上对应的⽂件 三、查看表结构 3.1. 语法 3.2. 示例 四、修改表 4.1. 语法 4.2. 示例 五、删除表 5.1. 语法 5.2.…

【DevOps】DevOps and CI/CD Pipelines

DevOps 是一种将开发与运维实践相结合的模式&#xff0c;旨在缩短软件开发周期并交付高质量软件。 DevOps 是什么&#xff1f; 开发团队与运维团队之间的协作 • 持续集成与持续交付&#xff08;CI/CD&#xff09; • 流程自动化 • 基础设施即代码&#xff08;IaC&#xff09;…

VS自定义静态库并在其他项目中使用

1、VS创建一个空项目或者静态库项目 2、右键项目 属性 修改生成文件类型 3、生成解决方案 4、复制.h文件和.lib文件作为静态库 5、创建一个新项目 测试使用新生成的静态库 在新项目UseStaticLib中加一个新文件夹lib&#xff0c;lib中放入上面的.h和.lib文件。 6、vs中右…

力扣32.最长有效括号(栈)

32. 最长有效括号 - 力扣&#xff08;LeetCode&#xff09; 代码区&#xff1a; #include<stack> #include<string> /*最长有效*/ class Solution { public:int longestValidParentheses(string s) {stack<int> st;int ans0;int ns.length();st.push(-1);fo…

vue3 项目中预览 word(.docx)文档方法

vue3 项目中预览 word&#xff08;.docx&#xff09;文档方法 通过 vue-office/docx 插件预览 docx 文档通过 vue-office/excel 插件预览 excel 文档通过 vue-office/pdf 插件预览 pdf 文档 安装插件 npm install vue-office/docx vue-demi示例代码 <template><Vu…

DHCP(Dynamic Host Configuration Protocol)原理深度解析

目录 一、DHCP 核心功能 二、DHCP 工作流程&#xff08;四阶段&#xff09; 三、关键技术机制 1. 中继代理&#xff08;Relay Agent&#xff09; 2. Option 82&#xff08;中继信息选项&#xff09; 3. 租期管理 4. 冲突检测 四、DHCP 与网络架构交互 1. MLAG 环境 2.…

创建login.api.js步骤和方法

依次创建 login.api.js、home.api.js...... login.api.js、home.api.js 差不多 导入到 main.js main.js 项目中使用

基于springboot二手交易平台(源码+lw+部署文档+讲解),源码可白嫖!

摘要 人类现已迈入二十一世纪&#xff0c;科学技术日新月异&#xff0c;经济、资讯等各方面都有了非常大的进步&#xff0c;尤其是资讯与网络技术的飞速发展&#xff0c;对政治、经济、军事、文化等各方面都有了极大的影响。 利用电脑网络的这些便利&#xff0c;发展一套二手交…

帕金森患者的生活重塑:从 “嘴” 开启康复之旅

当提到帕金森病&#xff0c;许多人会联想到震颤、僵硬和行动迟缓等症状。这种神经系统退行性疾病&#xff0c;给患者的生活带来了巨大的挑战。然而&#xff0c;你可知道&#xff0c;帕金森患者恢复正常生活&#xff0c;可以从 “嘴” 开始管理&#xff1f; 帕金森病在全球影响着…

JVM 为什么不使用引用计数算法?——深入解析 GC 策略

在 Java 中&#xff0c;垃圾回收&#xff08;Garbage Collection, GC&#xff09;是一个至关重要的功能&#xff0c;它能够自动管理内存&#xff0c;回收不再使用的对象&#xff0c;从而防止内存泄漏。然而&#xff0c;在垃圾回收的实现上&#xff0c;JVM 并未采用引用计数算法…

【HarmonyOS NEXT】EventHub和Emitter的使用场景与区别

一、EventHub是什么&#xff1f; 移动应用开发的同学应该比较了解EventHub&#xff0c;类似于EventBus。标准的事件广播通知&#xff0c;订阅&#xff0c;取消订阅的处理。EventHub模块提供了事件中心&#xff0c;提供订阅、取消订阅、触发事件的能力。 类似的框架工具有很多…

01-系统编程

一、程序和进程的区别&#xff1a; window系统&#xff1a; 1、程序存储在硬盘中&#xff0c;文件格式为.exe后缀&#xff0c;静态的 2、进程运行在内存中&#xff0c;动态的 Linux系统 1、程序存储在硬盘中&#xff0c;文件格式为.ELF&#xff08;可执行的链接文件&#…