C语言学习笔记——堆区空间申请(一)

C语言学习笔记

堆区空间申请(一)

栈区变量分析

  • 所有程序/软件的运行,都是由操作系统统一调配的,操作系统是程序的运行环境
  • 运行中的多个程序之间,内存是不交叉的
  • 程序结束后,操作系统还要释放其使用的资源,来给其他程序使用
  • 申请的空间种分为五个区域栈区(堆栈区),堆区,全局区,字符常量区,代码区,我们之前讲的这些定义变量、数组都是在内存的栈区存储。
  • 为什么分这么多区域?在实际生活中,这和公司差不多,部门分的细致,工作分发的就有针对性,效率就会高。
  • 由谁申请?
    栈区的特点:内存由系统申请,在变量生命周期结束时由系统释放,也就是说,在程序运行的时候,系统要多个任务,就是检测变量是否该释放了,简单来说,就是cpu要抽时间去执行这部分功能。所以,如果这种变量比较多,不加节制的定义的话,那CPU的额外的工作量就会加大,综合下来,程序的运行效率就会低下。
    堆区的特点:由我们程序员随时申请,由我们自己随时释放。
  • 实际应用中,系统会限制我们可使用的栈区空间大小(默认1M)stack overflow即为爆栈。
    这个大小可以从编译器的属性中修改,但尽量不修改,不够用了又不得不用再去修改。
    如果我们申请的空间,不由操作系统管理,而是我们自己申请与释放,那么就不会占用系统的额外资源了,这样我们就可以申请任意大小的空间了。

malloc函数介绍

  • 功能:在堆区空间中申请指定大小的,连续的,一段空间,并返回该空间的首地址。
    理论上,32位系统最大申请4G,64位系统最大16Tb(由安装内存决定)
  • 函数的原型:void *malloc(size_t size);
  • int *p = (int*)malloc(4);这样的一条语句即为申请一个4字节的int类型的堆区空间,并且定义一个指针变量p指向这个空间的首字节的地址(其中的4当然可以换成sizeof(int)),如果输入的是小数,也会被系统转换为整数,所以还是输入整数
    其实这里的4是int型的,更加标准的写法是4u,但是编译器会自动将有符号整形转换为无符号整型。
  • 头文件:malloc也是一个内建函数,所以头文件要求并没有那么高,但是更加标准的是<stdlib.h><malloc.h>

size_t详解

  • size_t在不同操作系统的软件里代表的被重命名的函数不一样,实测在32位的编译器中size_t == unsigned int,在64位的编译器中size_t == long unsigned int经过输出字节数可以证明(结果分别是4,8)

malloc申请空间的讨论

  • malloc(正常数)时会出现的内存碎片
    在malloc申请了一段指定字节数的空间后,即使后来将其释放,也不一定会被系统再次利用到。例如先申请了20B,后来要申请30B,则会形成内存碎片
  • malloc(0):
    会申请一个可用空间,但是其不可用
  • malloc(极限空间):
    申请的空间超出了内存,会得到返回值NULL,即为0;
    int *p = (int*)malloc(2*1024*1024*1024);(8G,32位程序中)会提示数据类型溢出;
    int *p = 2*1024*1024*1024 - 1甚至会提示两个错误,因为再乘法运算之后,数据类型就已溢出,再-1当然还在继续溢出;
    但是如果修改数据类型int *p = (int*)malloc(2u*1024u*1024u*1024u)就不会再有警告了,因为无符号的整形的范围是0~2^32-1。所以经常会在申请堆区空间之后进行一个if的判断,是否NULL == p,然后提示操作人员能否继续操作。

malloc空间赋值###

  • 强制类型转换:
    (类型*),malloc就是返回的void*,所以我们要转换成我们想要的类型,操作
  • 申请的空间不能初始化,不能像基本数据类型一样直接赋值,例如int a = 1,如果直接输出,会得到一个随机数,要是想给*p赋值,我们就要用*p = 0类似的语句来进行赋值
    那如果我们申请的堆区空间是这样的int *p = (int*)malloc(40),其实我们就是申请了一个数组,赋值方式、数值运算与数组完全一致。
  • 当然我们使用循环,对于数组的赋值并不是很方便,所以这里介绍一个新的函数memset
    memset的意义是将一段字节内的所有数值赋值为0。memset用法:int *p = (int*)malloc(40);memset(p, 0, 40);
    要点:切记memset是对内存赋值,memset(p,1,40);的结果是每一个4字节的数据,例如p[0],p[5]的数据全都是0000 0001 0000 0001 0000 0001 0000 0001即为16843009‬(10),所以这个函数经常用在将整个空间全部赋值为0。memset的头文件是<string.h>或者<memory.h>(一个int类型是4个字节,一个字节是8位二进制数)
  • 对于空间内数据的操作还是使用*p,这个是没有什么特殊的。

malloc注意点###

  • 不要申请的空间不够用,比如要申请4字节给int类型用,千万别申请三个,这样直接导致了越界,并且导致无法释放
  • 注意边界,这个有点像数组,例如int *p = (int*)malloc(4);*(p+1) = 12这样显然是越界操作,在编译时不会报错,但是运行时会崩溃
  • 一个指针指向了一块堆区空间,千万不要再指向另一块,因为相当于重新赋值,会导致内存丢失、造成内存泄露,且形成内存碎片,如果是在循环中会无限占用内存,导致死机
  • 13
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lanciberrr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值