先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
正文
- 顺序表
-
- 概念及结构
- 接口实现
-
- 初始化函数void SLInit(SL *psl);
- 销毁函数 void SLDestroy(SL *psl);
- 尾插函数void SLPushBack(SL* psl ,SLDataType x);
- 封装函数void SLCheckCapacity(SL* psl)
- 头插函数void SLPushFront(SL* psl, SLDataType x);
- 尾删函数void SLPopBack(SL* psl);
- 头删函数void SLPopFront(SL* psl);
- 任意下标插入函数void SLInsert(SL* psl, int pos, SLDataType x)
- 任意下标删除函数void SLErase(SL* psl, int pos)
- 查找数据函数int SLFind(SL* psl, int pos, SLDataType x)
- 初始化函数void SLInit(SL *psl);
- 概念及结构
- 数组越界的情况分析
感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒
个人主页
🥸🥸🥸
C语言
🐿️🐿️🐿️
C语言例题
🐣🐣🐣
python
🐓🐓🐓
数据结构C语言
下面是这篇文章会涉及到的知识,如果在阅读的过程中有疑惑的可以看一下
C语言函数介绍(详解)
C语言数组介绍(详解)
C语言深入理解指针(非常详细)(一)
动态内存管理(上)
动态内存管理(下)
自定义类型结构体(上)
自定义类型结构体(中)
自定义类型结构体(下)
线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列
常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线
但是在物理结构上并不一定是连续的
线性表在物理上存储时,通常以数组和链式结构的形式存储
顺序表
概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储
在数组上完成数据的增删查改
顺序表和数组的区别:
1:顺序表的存储必须是连续的,而数组是可以间隔的存储
2:顺序表在数组中存储时必须是从头开始依次存储,而数组可以在任意位置存储
顺序表一般可以分为:
静态顺序表:使用定长数组存储元素
缺点:N不知道给多少,可能会造成N太大或者太小
#define N 7
typedef int SLDataType;
typedef struct SeqList
{
SLDataType array[N];
size\_t size;
} SeqList;
动态顺序表:使用动态开辟的数组存储
typedef struct SeqList
{
SLDataType\* arry;
size\_t size;
size\_t capacity;
}SeqList;
接口实现
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用
所以现实中基本都是使用动态顺序表,根据需要动态的分配空间
大小,所以下面我们实现动态顺序表
首先我们先创建3个文件
1:SeqList.c是放一些功能函数具体实现的文件
2:SeqList.h是放一些功能函数函数名的文件
3:test.c是测试我们实现出的顺序表功能是否成功
之后就是实现函数了
初始化函数void SLInit(SL *psl);
SeqList.c文件
void SlInit(SL psl)
{
psl.a = NULL;
/\*psl.size=....;
psl.capacity=....;\*/
}
这里有一个常见的错误,就是我们在test.c中用初始化函数时往往会这样传
test.c文件
void TestSL1()
{
SL psl;
SLInit(psl);
}
因为我们的目的是为了初始化,所以在传参的时候我们要将地址传入函数
如果不传的话就相当于我们将顺序表的成员都拷贝了一遍,然后对拷贝到成员进行初始化,当出了这个初始化函数的时候拷贝到成员就会销毁
简单的来说就是没传入地址就是形参,而形参是实参的拷贝,出了作用域就会自动销毁,只有传入地址才可以更改实参
(如果形参和实参不是很清楚的可以看一下我上面链接中的 C语言函数介绍(详解))
所以正确的传入方式为
SeqList.c文件
void SlInit(SL \*psl)
{
assert(psl);//防止有人传空指针
psl ->a = NULL;//结构体用箭头解引用
psl->size=0;
psl->capacity=0;
}
test.c文件
void TestSL1()
{
SL s1;
SLInit(&s1);
}
销毁函数 void SLDestroy(SL *psl);
SeqList.c文件
void SLDestroy(SL\* psl)
{
assert(psl);//防止有人传空指针
if (psl->a!=NULL)
{
free(psl->a);//因为a是指针,所以要free a指向的空间
psl->a = NULL;//然后让a=NULL,不能让a指向被销毁的空间
psl->size = 0;
psl->capacity = 0;
}
}
尾插函数void SLPushBack(SL* psl ,SLDataType x);
尾插函数我们需要分情况讨论
1:尾插时有剩余的空间
2:尾插时没有剩余的空间
SeqList.c文件
void SLPushBack(SL\* psl, SLDataType x)
{
assert(psl);//防止有人传空指针
if ((psl->size) >= (psl->capacity))
{
int newCapacity = psl->capacity \* 2;
SLDataType\* a = realloc(psl->a, sizeof(SLDataType) \* newCapacity);
if (a == NULL)
{
perror("realloc fail");
return;
}
psl->capacity = newCapacity;
}
psl->a[psl->size] = x;
psl->size++;
}
这段代码的逻辑为判断有效长度是否大于总的长度,如果大于就意味着需要扩容
于是用newCapacity 等于2倍的capacity来扩大总长度(注意这里的2倍扩容并不一定非要2倍)
然后用realloc对空间扩容,因为realloc的函数特性(如果realloc不是很清楚可以看这篇文章最上面的链接内存函数部分),所以将realloc返回到地址给a
之后让capacity=newCapacity
然后对数组末尾进行插入,再将有效长度size加1
但是这段代码其实有几处的问题
1:在之前初始化函数中我们对于capacity的初始化为0,而这里的newCapacity是直接等于capacity*2,也就是newcapacity也为0
解决措施是在之前的初始化部分将capacity赋值为大于0的数
或者我们通过三目运算进行判断赋值
2:我们这段代码是将realloc返回的地址用a来接受,但是如果返回失败的话,a也就找不到之前的地址了
解决措施是我们用一个新的指针tmp来接受realloc返回到地址,然后判断是否扩容成功,成功的话就a=tmp
可能会有人认为a在之前初始化函数中a是空指针,而realloc(psl->a, sizeof(SLDataType) * newCapacity)中我们是对a进行扩容,但是a既然是空指针,我们就没有办法扩容,其实realloc是可以扩容的,因为当a是空指针的时候,realloc的功能就和malloc的功能一样了
封装函数void SLCheckCapacity(SL* psl)
因为对于后面的函数和尾插函数SLPushBack有一些代码是重合的,所以为了少写一些代码,我们将这些重合的写入这个封装函数SLCheckCapacity中
封装函数代码如下:
SeqList.c文件
void SLCheckCapacity(SL\* psl)
{
assert(psl);//防止有人传空指针
if ((psl->size) >= (psl->capacity))
{
int newCapacity = psl->capacity == 0 ? 4 : psl->capacity \* 2;
SLDataType\* tmp = realloc(psl->a, sizeof(SLDataType) \* newCapacity);//sizeof(SLDataType)一定要乘,否则会出现越界
if (tmp == NULL)
{
perror("realloc fail");
return;
}
psl->a = tmp;
psl->capacity = newCapacity;
}
头插函数void SLPushFront(SL* psl, SLDataType x);
对于头插函数我们并不能向前扩容,所以我们只能将数据向后移动
于是我们需要借助一个end指向顺序表最后的一块有效数据,end=size-1
然后通过a[end+1]=a[end],end–,使所有数据向后移动
最后再对a[0]进行头插
但是需要注意的是这里头插一次的时间复杂度为O[N],因此不能经常使用头插
SeqList.c文件
void SLPushFront(SL \* psl, SLDataType x)
{
assert(psl);//防止有人传空指针
SLCheckCapacity(psl);
int end = psl->size - 1;
while (end >= 0)
{
psl->a[end + 1] = psl->a[end];
### 给大家的福利
**零基础入门**
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
![](https://img-blog.csdnimg.cn/img_convert/95608e9062782d28f4f04f821405d99a.png)
同时每个成长路线对应的板块都有配套的视频提供:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a91b9e8100834e9291cfcf1695d8cd42.png#pic_center)
因篇幅有限,仅展示部分资料
网络安全面试题
![](https://img-blog.csdnimg.cn/img_convert/80674985176a4889f7bb130756893764.png)
绿盟护网行动
![](https://img-blog.csdnimg.cn/img_convert/9f3395407120bb0e1b5bf17bb6b6c743.png)
还有大家最喜欢的黑客技术
![](https://img-blog.csdnimg.cn/img_convert/5912337446dee53639406fead3d3f03c.jpeg)
**网络安全源码合集+工具包**
![](https://img-blog.csdnimg.cn/img_convert/5072ce807750c7ec721c2501c29cb7d5.png)
![](https://img-blog.csdnimg.cn/img_convert/4a5f4281817dc4613353c120c9543810.png)
**所有资料共282G**,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)**
![img](https://img-blog.csdnimg.cn/img_convert/0e74888e6c0b37edc7d0367c1c577efe.png)
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
blog.csdnimg.cn/img_convert/4a5f4281817dc4613353c120c9543810.png)
**所有资料共282G**,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)**
[外链图片转存中...(img-xlfDIhm7-1713666493513)]
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**