C语言进阶:动态内存管理_内存释放不置空

Return Value
None

Parameter
memblock - Previously allocated memory block to be freed

Remarks
The free function deallocates(解除) a memory block that was previously allocated. If memblock is NULL, the pointer is ignored. Attempting to free a memblock isn't allocated on heap may cause errors.

malloc函数在堆区上申请size个字节的空间,并返回该空间的起始地址。

free函数释放指针指向的动态开辟的空间,但不对指针造成任何影响。

函数用法
  • malloc返回通用类型的指针,将其强制转换为所需类型,并用该类型的指针维护该内存空间。
  • 开辟成功返回空间起始地址,开辟失败则返回NULL
  • 使用结束free释放内存以防内存泄漏,将指针置空避免成为野指针。
//申请空间
int\* p = (int\*)malloc(40);
//检查
if (p == NULL) {
    printf("%s\n", strerror(errno));
    return -1;
}
//使用
for (int i = 0; i < 10; i++) {
    \*(p + i) = i;
    printf("%d ", \*(p + i));
}
//释放空间
free(p);
//置空
p = NULL;

内存开辟函数 calloc
函数声明
void\* calloc( size\_t num, size\_t size );

Return Value
calloc returns a pointer to the allocated space. To get a pointer to a type other than void, use a type cast on the return value. 

Parameters
1. num - Number of elements
2. size - Length in bytes of each element

Remarks
The calloc function allocates storage space for an array of num elements, each of length size bytes. Each element is initialized to 0.

malloc函数在堆区上申请numsize大小的空间,返回起始地址并将内容初始化为0。

函数用法
int\* p = (int\*)calloc(10, sizeof(int));
if (p == NULL) {
    perror("");
    return -1;
}
for (int i = 0; i < 10; i++) {
    \*(p + i) = i;
    printf("%d ", p[i]);
}
free(p);
p = NULL;

内存调整函数 realloc
函数声明
void\* realloc( void\* memblock, size\_t size );

Return Value
realloc returns a void pointer to the reallocated memory block. The return value is NULL if there is not enough available memory to expand the block to the given size, then the original block is unchanged.

Parameters
1. memblock - Pointer to previously allocated memory block
2. size - New size in bytes

Remarks
The realloc function changes the size of an allocated memory block. The memblock parament points to the beginning of the memory block. If memblock is NULL, realloc behaves the same way as malloc. The contents of the block are unchanged, although the new block can be in a different location. 

realloc函数为已开辟的空间重新开辟大小。

函数用法
  • 当原空间后有足够大小时,就紧接原空间开辟剩余空间,并返回整个空间的起始地址。

  • 当原空间后无足够大小时,就在堆区寻找新空间,再将原空间的内容移动到新空间,返回新空间的地址且释放原空间。

  • 当剩余空间不够无法开辟时,增容失败,返回NULL
//1.
p = (int\*)realloc(p, 20 \* sizeof(int));
//2.
int\* ptr = (int\*)realloc(p, 20 \* sizeof(int));
if (ptr == NULL) {
    return -1;
}
p = ptr;

防止增容失败将原空间指针置空,故不可直接使用原指针接受返回值。判断非空后再赋给原指针。

常见的动态内存错误
1.不检查空指针
void test() {
	int\* p = (int\*)malloc(INT_MAX / 4);
	\*p = 20;
	free(p);
}

对指向动态开辟的空间的指针一定要做有效的判断。

2.越界访问
void test() {
	int i = 0;
	int\* p = (int\*)malloc(10 \* sizeof(int));
	if (NULL == p) {
		exit(EXIT_FAILURE);
	}
	for (int i = 0; i <= 10; i++) {
		\*(p + i) = i;
	}
	free(p);
    p = NULL;
}

作为程序员必须有意识地检查所写的代码是否有越界访问的问题。

3.释放非动态开辟内存
void test() {
	int a = 10;
	int\* p = &a;
	free(p);
    p = NULL;
}

不可用free释放非动态开辟的空间。

4.释放部分内存
int main()
{
	int\* p = (int\*)malloc(100);
	p++;
	free(p);
	return 0;
}

改变指向动态开辟内存的指针,内存将无法管理。释放不完全导致内存泄漏。

5.重复释放内存
void test() {
	int\* p = (int\*)malloc(100);
	free(p);
	free(p);
}

使用free释放已释放的空间,即访问非法内存。建议释放内存和指针置空搭配使用。

6.忘记释放内存
void test() {
    int \*p = (int\*)malloc(100);
    if(NULL != p) {
        \*p = 20;
    }
}
int main() {
    test();
    while(1);
}

使用结束不释放内存造成内存泄漏。程序不停止,系统也不会自动回收。

笔试题

调用下列test函数,解释运行结果。

Example 1
void GetMemory(char\* p) {
	p = (char\*)malloc(100);
}
void test() {
	char\* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
    free(str);
    str = NULL;
}

程序报错。

传值调用:并没有改变str的值仍为不予修改的空指针,可以使用二级指针接收str的地址。函数调用结束后指针销毁故无法释放空间以致内存泄漏。

Example 2
char\* GetMemory() {
	char p[] = "hello world";
	return p;
}
void test() {
	char\* str = NULL;
	str = GetMemory();
	printf(str);
    free(str);
    str = NULL;
}

程序打印随机值。

返回栈空间地址:数组p在函数内创建,出函数销毁,返回这部分空间的地址 ,属于访问非法空间。

Example 3
void GetMemory(char\*\* p,int num) {
	\*p = (char\*)malloc(num);
}
void test() {
	char\* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
	free(str);
    str = NULL;
}

程序运行成功,打印"hello"

传址调用:本题是例一的正确写法。

Example 4
void test(void) {
	char\* str = (char\*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL) {
		strcpy(str, "world");
		printf(str);
	}
}

程序报错。

野指针:动态开辟的内存释放后指针不置空,造成野指针访问非法内存。释放内存和指针置空应该搭配起来使用。

释放空间,销毁空间都是将内存空间归还给操作系统,即将此空间的使用权限归还操作系统。虽不会改变空间内容以致打印出所谓的“正确结果”,但可能在之后被操作系统分配给其他程序时发生修改。但无论改变与否,一旦空间归还后再去访问就是访问非法内存。

C/C++内存划分
用例展示

根据下列创建的各种变量,分析内存的划分。

int globalVar = 1;
static int staticGlobalVar = 1;
int main()
{
	static int staticVar = 1;
	
	int localVar = 1;
	int num1[10] = { 1,2,3,4 };
	char char2[] = "abcd";
	char\* pChar3 = "abcd";
	int\* ptr1 = (int\*)malloc(4 \* sizeof(int));
	int\* ptr2 = (int\*)calloc(4, sizeof(int));
	int\* ptr3 = (int\*)realloc(ptr2, 4 \* sizeof(int));

	free(ptr1);
	free(ptr3);
	return 0;
}

  1. globalVal,staticGobalVar,staticVar分别是全局变量和静态变量,在数据段上创建。
  2. localVarnum,char2,pchar以及ptr本身都是局部变量,都是在栈区上创建的。
  3. malloc,calloc,realloc都是在堆区上开辟的内存块,由指针ptr指向而已。
内存划分图示

  1. 栈区(stack):执行函数时,函数的局部变量都会在栈区上创建。压栈:从栈顶向下开辟空间,弹栈:从栈底向上释放空间。
  2. 堆区(heap):一般由程序员分配和释放,从堆低向上开辟空间,堆顶向下释放空间。在程序结束后也被操作系统会自动回收。
  3. 数据段(静态区):存放全局变量,静态数据。变量本在栈上创建,被static修饰后放在常量区,程序结束后由系统释放。
  4. 代码段(常量区):存放可执行代码和只读常量。

语言学习时期,仅对内存作此了解即可。内核空间和内存映射段会在操作系统中学习,此处不再深入研究。

如何自学黑客&网络安全

黑客零基础入门学习路线&规划

初级黑客
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)

2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等

3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)

4、计算机网络基础(一周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现

5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固

6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)
恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k

到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?

如果你想要入坑黑客&网络安全,笔者给大家准备了一份:282G全网最全的网络安全资料包评论区留言即可领取!

7、脚本编程(初级/中级/高级)
在网络安全领域。是否具备编程能力是“脚本小子”和真正黑客的本质区别。在实际的渗透测试过程中,面对复杂多变的网络环境,当常用工具不能满足实际需求的时候,往往需要对现有工具进行扩展,或者编写符合我们要求的工具、自动化脚本,这个时候就需要具备一定的编程能力。在分秒必争的CTF竞赛中,想要高效地使用自制的脚本工具来实现各种目的,更是需要拥有编程能力.

如果你零基础入门,笔者建议选择脚本语言Python/PHP/Go/Java中的一种,对常用库进行编程学习;搭建开发环境和选择IDE,PHP环境推荐Wamp和XAMPP, IDE强烈推荐Sublime;·Python编程学习,学习内容包含:语法、正则、文件、 网络、多线程等常用库,推荐《Python核心编程》,不要看完;·用Python编写漏洞的exp,然后写一个简单的网络爬虫;·PHP基本语法学习并书写一个简单的博客系统;熟悉MVC架构,并试着学习一个PHP框架或者Python框架 (可选);·了解Bootstrap的布局或者CSS。

8、超级黑客
这部分内容对零基础的同学来说还比较遥远,就不展开细说了,附上学习路线。
img

网络安全工程师企业级学习路线

img
如图片过大被平台压缩导致看不清的话,评论区点赞和评论区留言获取吧。我都会回复的

视频配套资料&国内外网安书籍、文档&工具

当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

img
一些笔者自己买的、其他平台白嫖不到的视频教程。
img

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

需要这份系统化资料的朋友,可以点击这里获取

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值