C语言中,通过malloc()函数申请的内存,free()函数释放内存,只传入一个地址,为什么能知道释放多大的内存?

         在编写C/C++程序时,我们会经常和内存打交道,手动申请内存、释放内存,不知道大家有没有想过,malloc()函数申请的一块内存,用完后我们会调用free()函数释放内存,而free()函数只传入了一个地址,怎么能知道要释放多大的内存呢?接下来,我们带着这个疑问阅读下面的内容,看完就明白了。

   在开始正式内容前,大家先看一下这个图,相信经常写C/C++程序的小伙伴都陌生。

       图1

         一般出现这个问题,都是我们操作了非法的内存地址,导致释放内存时候地址值不对,发生错误。

         我们申请的内存假如是128字节,实际上系统给我们分配的内存大小是:128+16 = 144字节。前面有16字节是存储这块内存的信息,我们可用的内存是下图绿色区域,即我们申请的大小。

          free()函数拿到图2箭头所指位置,然后先左偏移16个字节,便获取到该内存块信息,便可以释放内存。 图1所示的错误,是因为我们修改了内存块信息,即图2中灰色区域导致的。

       图2

查看内存块头部信息:

    写一个简单的申请内存程序。  


#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    uint8_t *buffer1 = (uint8_t*)malloc(32);  //申请32字节内存
    uint8_t *buffer2 = (uint8_t*)malloc(64);  //申请64字节内存

    memset(buffer1, 0x55, 32);                //把32字节内存区域使用0x55填充
    memset(buffer2, 0xAA, 64);                //把64字节内存区域使用0xAA填充

    printf("stuff memory finish!\n");

    getchar();                                //输入任意字符,往下执行

    free(buffer1);                            //释放内存1
    printf("free buffer1...\n");

    free(buffer2);                            //释放内存2
    printf("free buffer2...\n");

    return 0;
}

        使用Linux 下的GDB对程序进行调试,查看内存值。  在getchar(); 这个位置打一个断点,查看此时内存信息。图3中绿色方框中是内存块头部信息,红色方框是用户所使用的内存。buffer1已经被我们使用0x55填充了,buffer2被我们使用0xaa填充了。注:图3中是以十六进制显示的。

       图3

         绿色方框中的buffer1头部信息如图4所示,只有一个0x31的值,其他都是0,0x31(十进制: 49), 49 = 32 + 16 +1,32字节是我们malloc()函数申请的大小,16字节是头部信息大小,还有1字节的偏移,所以free()函数拿到这块地址,根据头部信息才能正确的释放内存。若修改了0x31及其右边区域的值,释放内存时候将发生图1所示错误。

       图4

         图5绿色方框是buffer2的内存块头部信息,有一个值0x51(十进制:81),81=64 + 16 + 1,64字节是我们使用malloc()函数申请的大小,16字节是内存块头部信息,1字节的偏移。

       图5

        释放内存后,内存中的值:(注:在64位系统中,一个指针的大小占8个字节,在32位系统中,一个指针大小占4个字节。,小C使用的是64位系统,即一个指针占8个字节)。释放内存后,buffer1、buffer2起始位置向后8个字节被置0了,图5红色线标志所示。

       图6

我是小C,欢迎大家关注、点赞支持,我们一起交流讨论学习!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值