C++入门 vector的使用 + 进阶【模拟实现】_c,2024年最新1307页阿里网络安全面试全套真题解析在互联网火了

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
img

正文

	}
}

}


**vs下capacity是按1.5倍增长的**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/274b67f8df8a4c6a86938786cf3278a2.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_10,color_FFFFFF,t_70,g_se,x_16)


**在linux下以2倍增长**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6144b4786cc44aad9a65eb02e2b70c7e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)


### 增删查改




| vector增删查改 | 接口说明 |
| --- | --- |
| push\_back(重点) | 尾插 |
| pop\_back (重点) | 尾删 |
| find | 查找。(注意这个是算法模块实现,不是vector的成员接口) |
| insert | 在position之前插入val |
| erase | 删除position位置的数据 |
| swap | 交换两个vector的数据空间 |
| operator[] (重点) | 返回此下标位置的值 |



void func1()
{
//插入5个值
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);

for (auto val : v) 
{
	cout << val << " ";
}
cout << endl;
//在一段迭代去区间查找值为2的元素,找到返回此位置的迭代器,
//没有找到就返回end()处的迭代器
vector<int>::iterator pos = find(v.begin(),v.end(),2);
if (pos != v.end()) 
{
	//将值插入到pos位置之前
	v.insert(pos,30);
}

for (auto val : v)
{
	cout << val << " ";
}
cout << endl;
//在一段迭代去区间查找值为2的元素,找到返回此位置的迭代器,
//没有找到就返回end()处的迭代器
pos = find(v.begin(), v.end(), 30);
if (pos != v.end()) 
{
	//删除pos位置的值
	v.erase(pos);
}

for (auto val : v)
{
	cout << val << " ";
}

}


### 迭代器失效问题探讨


**野指针问题**



//测试二
void func2()
{
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);

vector<int>::iterator it = v.begin();
while (it != v.end()) 
{
	cout << \*it << " ";
	it++;
}
cout << endl;
//查找 pos位置,找到后返回此位置的迭代器
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
//在pos位置前插入10,空间会扩容并释放旧的空间,
//重新分配一块新的空间,由于旧空间已经被释放完了,所以不可访问
v.insert(pos,10);
it = v.begin();
while (it != v.end())
{
	cout << \*it << " ";
	it++;
}

cout << endl;
//pos是野指针,使用pos去访问旧空间是一个隐患
v.erase(pos);
it = v.begin();
while (it != v.end())
{
	cout << \*it << " ";
	it++;
}

}


**这个程序的运行是会存在错误的,错误的原因是pos还在访问那块旧的空间,pos迭代器却早已经失效了,旧空间释放后内存使用权限已经归还给操作系统了,而pos还指向那块旧的空间,v.erase(pos);这句代码就是去访问一块非法内存,所以就会程序崩溃**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/cab959ed5b694071a440da101bae3b31.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)  
 图解:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/1cc47aab867b494bb49428d66e7e7574.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)


**下面这块程序的功能是将容器中所有的偶数都删除掉,只保留奇数数据**  
 这段程序在不同的平台上是不一样的



//测试一
void func1()
{
vector 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);

vector<int>::iterator it = v.begin();
while (it != v.end())
{
	if (\*it % 2 == 0) 
	{
		v.erase(it);
	}
	it++;
}
for (auto e : v) 
{
	cout << e << " ";
}

}


在vs上,程序就直接崩溃了  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/8acbdc12b36943c282c8b0060dc4c01b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)  
 在linux上出现段错误  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/30e80c2b0e534aebb54030757f909962.png)  
 图解析:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/58f35e01c3214b3fac935bbabee74469.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)  
 从图中我们可以看出it每次删元素的时候都会跳过一个元素,end的位置每次也都在发生变化,直到删除6的时候 it 和 end已经开始错开了,分道扬镳,此后再也不会相遇,it此时就是野指针了,访问了一块非法的内存,但是在linux上平台上我们只需要将尾插一个7(奇数)就能解决这个问题,vs下无论是最后一个值是奇数还是偶数都会报错,it已经失效,编译器会直接对it++检查  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/d9f1ce02d50e4338bf25d444410af3d4.png)  
 是因为当插入7的时候刚好检查到最后一个位置不会再erase掉,it再往后迭代的时候就遇到了end,循环也就终止了,但是这段代码还是错误的代码,因为不同的平台跑出的结果是不一样的


解决方案



vector::iterator it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
//erase删除it位置的元素后,会返回it位置的下一个位置,
//再回去检查这个元素是否是偶数
it = v.erase(it);
}
else
{
it++;
}
}


总结:  
 insert和erase都会导致迭代器失效  
 1、insert(it, x) 或者 erase(it) 以后迭代器的意义变了  
 2、insert(it, x) 或者 erase(it) 以后it变成了野指针


## vector模拟实现



namespace mzt
{
template
class vector
{
public:
typedef T* iterator;
iterator begin() { return _start; }
iterator end() { return _finish; }
size_t capacity() { return _endofstroage - _start; }
size_t size() { return _finish - _start; }

	vector()
		:\_start(nullptr)
		, \_finish(nullptr)
		, \_endofstroage(nullptr)
	{ }
	vector(vector<T>& v)
		:\_start(nullptr)
		,\_finish(nullptr)
		,\_endofstroage(nullptr)
	{
		reserve(v.capacity());
		for (auto &e : v) 
		{
			push\_back(e);
		}
	}

	void swap(vector<T>& v)
	{
		::swap(_start,v._start);
		::swap(_finish,v._finish);
		::swap(_endofstroage,v._endofstroage);
	}
	vector<T>& operator=(vector<T> v)
	{
		if (this != &v) 
		{
			swap(v);
		}
		return \*this;
	}

	void reserve(size_t n) 
	{
		size_t sz = size();
		T\* tmp = new T[n];
		if (n > capacity())
		{
			//memcpy(tmp,\_start,sizeof(T) \* n);
			if (_start)
			{
				for (size_t i = 0; i < sz; i++)
				{
					tmp[i] = _start[i];
				}
				delete[]_start;
			}

			_start = tmp; 
			_finish = _start + sz;
			_endofstroage = _start + n;
		}
	}
	//尾插
	void push\_back(const T& v)
	{
		if (_finish == _endofstroage)
		{
			size_t newcapacity = capacity() == 0 ? 4 : capacity() \* 2;
			reserve(newcapacity);
		}
		\*_finish++ = v;
	}
	void erase() 
	{
		assert(!empty());
		--_finish;
	}

	void resize(size_t n,T a = T()) 
	{
		if (n < capacity()) 
		{
			_finish = _start + n;
		}
		else 
		{
			if (n > capacity()) 
			{
				reserve(n);
			}
			while (_finish < _endofstroage) 
			{
				\*_finish++ = a;
			}
		}
	}
	size_t operator[](size_t n) 
	{
		assert(n < size());
		return _start[n];
	}

	iterator insert(iterator pos, const T& x)
	{
		if (_finish == _endofstroage) 
		{
			size_t len = pos - _start;
			size_t newcapacity = capacity() == 0 ? 4 : capacity() \* 2;
			reserve(newcapacity);
			//pos失效后重新计算pos的位置
			pos = _start + len;
		}
		iterator end = _finish - 1;
		while (end >= pos) 
		{
			\*(end + 1) = \*end;
			end--;
		}	
		\*pos = x;
		++_finish;
		return pos;
	}
	iterator erase(iterator pos)
	{
		assert(!empty());
		iterator it = pos + 1;
		while (it != _finish) 
		{
			\*(it - 1) = \*it;
			it++;
		}
		--_finish;
		return pos;
	}

	bool empty() { return _start == _finish; }

	~vector() 
	{
		if (_start) 
		{
			delete[] _start;
		}
		_start = _finish = _endofstroage = __nullptr;
	}

private:
	iterator _start;
	iterator _finish;
	iterator _endofstroage;
};

}


**私有成员**



iterator _start;//返回起始位置
iterator _finish;//返回最后一个元素的下一个位置
iterator _endofstroage;//返回空间的结束标记位置


### reserve



//返回最后一个元素的下一个位置
size_t size()const
{
return _finish - _start;//指针相减计算中间差的元素个数
}

void reserve(size_t n)
{
if(n > capapcity())
{
size_t sz = size();
//提前备份好sz大小,防止扩容后_start 指向了新的空间,
T* tmp = new T[n];
if (_start)
{
//旧的空间_start的值拷贝到新空间上tmp上
//memcpy(tmp, _start, sizeof(T) * n);
//memcpy针对内置类型是可以的,但是如果针对
//的是自定义类型的话,可能会存在浅拷贝的问题,
//所以不管T类型是否是自定义类型也好,内置类型也好
//一律都去调用T类型的operator=
for(size_t i = 0; i < sz; i++)
{
tmp[i] = _start[i];
}
//回收旧空间
delete[] _start;
}
_start = tmp;
_finish = _start + sz;//提前备份sz的大小,防止计算错误
//错误示范:_finish = _start + size();
//_start 已经指向了一块新分配的空间地址就变了
_endofstroage = _start + n;
//实际空间开多大
}
}



> 
> 这里需要注意的是\_start = tmp;的时候\_start 就已经指向新的空间了,如果使用\_start + size()回去调用size函数  
>  那就成了这样了:\_start + (\_finish - \_start),那就会很有可能是一个负数了,当然我们的编译器也不会这么傻  
>  ![在这里插入图片描述](https://img-blog.csdnimg.cn/629d464006c04a92ac53431343c39edf.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)  
>  当断点执行到这一行的时候\_finish指向的位置还是0x00000000,那么\_finish压根就没变,解决办法,防止\_start指向新空间后地址变了,我们先提前备份好size个数据
> 
> 
> 



void push_back(const T& v)
{
//满了考虑扩容
if (_finish == _endofstroage)
{
//尾插数据的时候提前计算增容大小
size_t newcapacity = capacity() == 0 ? 4
: capacity() * 2;
reserve(newcapacity);
}
//往这块空间填充值,_finish再往后挪动
*_finish = v;
_finish++;
}



> 
> 跟顺序表的尾插类似,考虑扩容就行
> 
> 
> 


### 迭代器



typedef T* iterator;

//返回开始位置
iterator begin() const
{ return _start; }
//返回最后一个元素的下一个位置
iterator end() const
{ return _finish; }



> 
> 提一句,范围for的底层是支持迭代器的,迭代器原理类似指针
> 
> 
> 


### 空间容量


下面的接口函数我们直接对照图就可以清晰地理解  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/27b1b57c8c4740dc9e6d2135ed27869e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)



//返回总空间大小
size_t capacity() const
{
return _endofstroage - _start;
}
//返回有效数据个数
size_t size()const
{
return _finish - _start;
}


### 删除



void erase()
{
assert(!empty());
//指针往前挪动,就相当于减去一个数据
–_finish;
}
//判空,如果_start 和 _finish都在一个起始位置就说明容器为空
bool empty() const{ return _start == _finish; }


**resize**



void resize(size_t n,T a = T())
{
//如果n小于实际空间的大小那么就做缩容处理
if (n < capacity())
{
_finish = _start + n;
}
else
{
//如果n > capacity()个空间,就先扩容
if (n > capacity())
{
reserve(n);
}
//空间够就对多出来的空间初始化
while (_finish < _endofstroage)
{
*_finish++ = a;
}
}
}

给大家的福利

零基础入门

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

同时每个成长路线对应的板块都有配套的视频提供:

在这里插入图片描述

因篇幅有限,仅展示部分资料

网络安全面试题

绿盟护网行动

还有大家最喜欢的黑客技术

网络安全源码合集+工具包

所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

喜欢的黑客技术

网络安全源码合集+工具包

所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
[外链图片转存中…(img-IDhfh6P3-1713303731133)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 22
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值