C语言基础--内存管理

 一.C语言引入

作为一个嵌入式工程师,说起c语言一定不会陌生,之前有位老师说越接近底层程序越高效,处理器越喜欢,相反人编程难度就大了许多,现在有许多高级语言,包括现在大火的python几行代码就能搞定,所以C/C++ CPU执行效率更高,python编写效率更高,所以根据不同的应用场景选择合适的语言。

 

发展历史:

贝尔实验室   UNIX   c语言

 

接下来你会觉得我会说if else 然后 数组 指针,念书式的顺一遍,当然不是啦,通过这么长时间的工作,发现数组,指针,结构体,内存分配等知识越来越重要,现在我们着重说说这部分,老说些基础的知识,应用的时候还是不知道咋用。

 

二.C语言的内存管理模型

在以前的学习中,我们也学习过,c/C++定义了4个内存区间

代码区  静态变量区(全局变量) 栈区(局部变量) 堆区(动态存储区)

 

栈区:由编译器自动分配内存,存放函数的参数,局部变量,自动变量,自动回收。

堆区:由程序员分配释放(malloc, free)

静态区:所有的 全局变量+静态变量(static)+字符串常量

代码区:所有可执行代码(指令,常量字符串)加载到代码区

 

注:栈区生命周期:函数调用结束,内存空间就会释放

静态区生命周期:整个程序结束内存才会释放。(整个源程序)

这里主要说明要了解局部变量,全局变量,静态变量等的生命周期,在应用中指针操作,可能语法上并不会出错,但是执行结果是错误的,找的时候够你受的。

就加了一个static,变量就从栈区的生命周期变为了静态变量的生命周期,加static就运行正常,不加就打印数据错误。

 

以后我们在编程的时候就能做到心中有数,定义什么样的数据类型,他们都运行在什么样的内存空间,使内存得到充分的合理的利用。

比如我们明确数据占用多少内存,那么数据量小的时候我们用栈,较大时候用堆

不知道数据量大小,可能较大时,用堆

需要动态创建分配,用堆。(防止越界访问)

P作为一个指针放在栈上,执向堆空间上的内存地址,当输入超过了堆的内存分配空间,P就会出现了一个越界访问,出现报错。

 

还有就是我们写了一个递归函数,如果没写好出口,就会容易出现栈溢出错误。

 

内存分配举例:

 

 

三.应用中的思考

在我们的单片机编程中,程序通过软件进行编译输出如下信息

Program Size: Code=10904  RO-data=940  RW-data=40  ZI-data=1736  (stm32程序)

 

Code是代码占用的空间;

RO-data是 Read Only 只读常量的大小,如const型;

RW-data是(Read Write) 初始化了的可读写变量的大小;

ZI-data是(Zero Initialize) 没有初始化的可读写变量的大小。ZI-data不会被算做代码里因为不会被初始化;

烧写的时候是FLASH中的被占用的空间为:Code + RO Data + RW Data

程序运行的时候,芯片内部RAM使用的空间为: RW Data + ZI Data

比如我们经常遇到的内存溢出错误就是RW Data + ZI Data 大于了我们芯片的内存空间。

 

四.详细理解动态内存分配

在程序中我们经常用到动态内存分配,那么详细说一下动态内存分配。

 

我们在实际的代码开发中,有些操作对象只有在程序运行时才能确定,所以需要动态内存分配。所有的动态内存分配都是在堆上进行的。

这里我们就会想到很熟悉的两个函数,malloc free两个函数,动态内存的生命周期由我们决定,有了掌控权感觉自己拽拽的,但是也导致程序出现很多bug,还有很多隐患。所以要求在使用的时候,理解要深入,编写要规范。

 

堆需要显示释放,也需要显示初始化。(自己编程控制)

 

例:

Char *p

P =(char *)malloc(10*sizeof(char)); //显示转换为所需要的指针类型

If(p == NULL){ return 0}; //判断是否内存申请成功,以前都忽视,不然傻呵呵做半天,内存都 没成功,做毛线啊。

Free(P); //一般我们申请了内存就要释放,不然就会内存占用越来越多,同时释放一部分内 存是不被允许的。

 

现在我们分配了10个字符的内存空间,假如现在我们输入超过了分配的大小。

P指针位于栈上,指向位于堆上的内存地址,超过分配大小,P还会继续向下指,就会出现越界访问。所以在编程的时候要注意。

 

Free(P)实际上删除的肯定就是p指向的堆空间,free成功了,分配的空间肯定就不能使了,这些都很好理解。但是当执行完这个操作,P指针一直保存了分配空间的起始地址(空悬指针),这时候如果不当操作,肯定也会出问题,所以我们在free(P),之后 加P=NULL;操作代码更规范。

 

只申请不释放,会造成内存泄漏,但是申请了频繁释放也会出现问题。

比如我们free了两次,也会出现问题,当我们释放了一次之后,内存就变为了私有内存了,能够再次被分配,不是你的你在释放,谁不跟你急啊。

 

所以动态分配的时候,整个生命周期我们要心里有数。

 

野指针:不是NULL指针,是指向垃圾内存的指针

原因:指针变量没有初始化

P被free后,没有置为NULL

指针操作越界。

 

这个没有进行初始化,就进行了赋值。

 

总结:

typedef struct student{

int no;

char name[20];

float score;

}Stu;


Stu * get_info()

{

Stu *p;

if((p=(Stu *)malloc(sizeof(stu)))==NULL){

printf(“malloc failed\n”);

return NULL;

}

p->no =1;

strcpy(p->name,”tom”);

p->score =90;

return p;

}

int main(int argc,const char *argv[])

{

Stu *s;

if((s=get_info())==NULL){

return 0;

}

printf(“student info:%d %s %.2f\n”,s->no,s->name,s->score);

return 0;

}

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值