嵌入式学习-C语言-内存管理

记录每次学习的过程,总结学习的内容,希望能给到自己和别人帮助。

嵌入式学习-C语言-内存管理

C代码编译过程

从编译到生成可执行文件的过程:
● 预处理
○ 宏定义展开、头文件展开、条件编译,这里并不会检查语法
● 编译
○ 检查语法,将预处理后文件编译生成汇编文件
● 汇编
○ 将汇编文件生成目标文件(二进制文件)
● 链接
○ 将目标文件链接为可执行程序

进程的内存分布

● 程序运行起来(没有结束前)就是一个进程
● 对于一个C语言程序而言,内存空间主要由五个部分组成 代码区(text)、数据区(data)、未初始化数据区(bss),堆(heap) 和 栈(stack) 组成
○ 有些人直接把data和bss合起来叫做静态区或全局区
在这里插入图片描述
代码区: 代码文件内容,函数
文字常量区(data): char * p =“hello”;//常量 不可修改的 (文字常量区,不能修改)
初始化数据(data):已经初始化的全局变量 int a=10; //放在函数外表面的(全局变量,整个程序结束才释放)
未初始化的全局变量 int a;
栈区 局部变量(离开代码块{},就自动释放)
堆区 全局变量例如 static(需要用户手动管理的,申请空间,释放空间)(用户不释放,只要程序没有结束,一直存在)

不一样的区,不一样的功能 不同内存决定不一样的生命周期
在这里插入图片描述
● 代码区(text segment)
○ 加载的是可执行文件代码段,所有的可执行代码都加载到代码区,这块内存是不可以在运行期间修改的。
● 未初始化数据区(BSS)
○ 加载的是可执行文件BSS段,位置可以分开亦可以紧靠数据段,存储于数据段的数据(全局未初始化,静态未初始化数据)的生存周期为整个程序运行过程。
● 全局初始化数据区/静态数据区(data segment)
○ 加载的是可执行文件数据段,存储于数据段(全局初始化,静态初始化数据,文字常量(只读))的数据的生存周期为整个程序运行过程。
● 栈区(stack)
○ 栈是一种先进后出的内存结构,由编译器自动分配释放,存放函数的参数值、返回值、局部变量等。在程序运行过程中实时加载和释放,因此,局部变量的生存周期为申请到释放该段栈空间。
● 堆区(heap)
○ 堆是一个大容器,它的容量要远远大于栈,但没有栈那样先进后出的顺序。用于动态内存分配。堆在内存中位于BSS区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。

堆区内存的使用

申请 malloc( ) ->释放free( )
在这里插入图片描述
申请一个malloc空间,p指向这个malloc空间,存着malloc空间的地址。所以*p操作的是指针变量锁指向的空间,操作堆区空间。
free( )函数,释放的是malloc空间,因为p是变量不需要手动释放,只需要释放p指向的手动申请的malloc空间。

跟自动分配空间和指针等一样,只不过这个空间是系统分配还是自己申请。

malloc()

#include <stdlib.h>
void *malloc(size_t size);
功能:在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域,用来存放类型说明符指定的类型。
	分配的内存空间内容不确定。
参数:
	size:需要分配内存大小(单位:字节)
返回值:
    成功:分配空间的起始地址
    失败:NULL

free()

#include <stdlib.h>
void free(void *ptr);
功能:释放ptr所指向的一块内存空间,ptr是一个任意类型的指针变量,指向被释放区域的首地址。
	对同一内存空间多次释放会出错。
参数:
	ptr:需要释放空间的首地址,被释放区应是由malloc函数所分配的区域。
返回值:无

思考:为什么我释放了空间,指针还是能获取到对应的地址

#include <stdio.h>
#include <stdlib.h>
int main() {
	int * p = malloc(sizeof(int));
	*p = 123;
	printf("%p\n", p);
	printf("*p=%d\n", *p);
	free(p);

	*p = 333;
	printf("%p\n", p);
	printf("*p=%d\n", *p);
	
	//结果:
//	000002437d2f1430
//	*p=123
//	000002437d2f1430
//	*p=333
	
	//为什么我释放了空间,指针还是能获取到对应的地址
	/*
	  首先,我们先理解一下malloc函数的作用。
	  在C语言中,malloc函数用于在内存中动态分配一定大小的未初始化空间,并返回这个空间的指针。
	  当你使用free函数后,这个空间会被释放,意味着你不能再次使用这个空间,否则可能会出现不可预期的行为,比如数据错误、程序崩溃等。
	  
	  然而,这里的代码有一些错误。
	  当使用free(p)释放了p指向的空间后,p自身并不一定被置为NULL。
	  也就是说,p仍然会保持之前指向的地址。但是这个地址现在已经是无效的,因为它的空间已经被释放了。
	  如果你再次尝试通过这个指针去访问或者修改数据,那么就会出现问题。
	  
	  这里释放了空间之后,再次尝试通过p去访问或者修改数据,这是不安全的。
	  虽然看起来可能没有立即出现问题,但这是一种潜在的错误源。
	  在实际编程中,释放空间后,应该避免再次使用这个空间。
	  如果想要安全地释放空间并重置指针,你可以这样做:(释放空间的同时,将指针指向也重置成null)
	  free(p);  
	  p = NULL; // 将指针重置为 NULL


	  在这个代码中,当调用free(p)释放空间后,你将p置为NULL。
	  这样,你就明确地告诉了程序这个指针不再指向任何有效的内存空间。
	  当再次尝试使用这个指针时,程序就会发现它是指向无效的内存空间(也就是NULL),从而避免出现错误。
	  
	 */
	return 0;
}

申请数组
在这里插入图片描述
返回堆区地址
在这里插入图片描述

凡心所向,素履以往,生如逆旅,一苇以航。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值