0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

realloc函数和free函数的实验及注意事项

C语言编程学习基地 来源:C语言编程学习基地 作者:Mr_Li_ 2022-10-21 16:51 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

realloc函数

realloc()函数可以重用或扩展以前用malloc()、calloc()及realloc()函数自身分配的内存。

函数原型:

extern void *realloc(void *mem_address, unsigned int newsize);
//指针名 = (数据类型*) realloc (要改变内存大小的指针名,新的大小)。
//新的大小一定要大于原来的大小,不然的话会导致数据丢失!
//如果newsize大小为0,那么释放mem_address指向的内存,并返回NULL。

先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将 mem_address返回,如果空间不够,先按照 newsize 指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来 mem_address 所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。

1、 realloc()函数需两个参数:一个是包含地址的指针(该地址由之前的malloc()、calloc()或realloc()函数返回),另一个是要新分配的内存字节数。

2、 realloc()函数分配第二个参数指定的内存量,并把第一个参数指针指向的之前分配的内容复制到新配的内存中,且复制的内容长度等于新旧内存区域中较小的那一个。即新内存大于原内存,则原内存所有内容复制到新内存,如果新内存小于原内存,只复制长度等于新内存空间的内容。

3、realloc()函数的第一个参数若为空指针,相当于分配第二个参数指定的新内存空间,此时等价于malloc()、calloc()或realloc()函数。

4、如果是将分配的内存扩大,则有以下3种情况:

1) 如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc()将返回原指针。

2) 如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块地址位置。

3) 如果申请失败,将返回NULL,此时,原来的指针仍然有效。

注意事项:

1、第一个参数要么是空指针,要么是指向以前分配的内存。如果不指向以前分配的内存或指向已释放的内存,结果就是不确定的。

2、 如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放掉原来的指针,重新返回一个指针,虽然返回的指针有可能和原来的指针一样,即不能再次释放掉原来的指针。

返回值:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

注意:这里原始内存中的数据还是保持不变的。当内存不再使用时,应使用free()等函数将内存块释放

#include
#include
int main()
{
  int i;
  int *t;


  int*pn = (int*)malloc(10 * sizeof(int));//这里只是申请10个int的空间
  t = pn;


  for (i = 0; i < 10; i++) {  //赋值
    pn[i] = i;
  }


          //如果将这里的数值改大就将有可能出现空闲空间不足,从而申请一块新内存
  pn = (int*)realloc(pn, 20 * sizeof(int)); //多扩充10个int空间加上之前的就是一共20个int


  for (i = 10; i < 20; i++) {//再赋值  注意从第10个开始的
    pn[i] = i;
  }


  for (i = 0; i < 20; i++) {//输出
    printf("%3d", pn[i]);
  }


  printf("
");
  printf("p=%p 
t=%p
", pn, t);//输出地址




  free(pn);//释放空间
  pn = NULL;//指针指空


  return 0;




}


如果申请空间的数值较小,原来申请的动态内存后面还有空余内存,系统将直接在原内存空间后面扩容
并返回原动态空间基地址;如果申请空间的数值较大,原来申请的空间后面没有足够大的空间扩容,
系统将重新申请一块新的内存,并把原来空间的内容拷贝过去,原来空间OS自动free;如果申请空间的数值非常大,
系统内存申请失败,返回NULL,原来的内存不会释放。注意:如果扩容后的内存空间较原空间小,将会出现数据丢失,
如果直接realloc(p, 0);相当于free(p).

使用总结:

(1)realloc失败的时候,返回NULL

(2)realloc失败的时候,原来的内存不改变,不会释放也不会移动

(3)假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址

(4)如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。

(5)传递给realloc的指针必须是先前通过malloc(),calloc(), 或realloc()分配的

(6)传递给realloc的指针可以为空,等同于malloc。

malloc与free函数

malloc中文叫动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存,且分配的大小就是程序要求的大小。

函数原型:

void * malloc(size_t size);


在以前 malloc返回的是char型指针,新的ANSIC标准规定,该函数返回为void型指针,因此必要时要进行类型转换。
它能向系统申请分配一个长度为num_bytes(或size)个字节的内存块。


其作用是在内存的动态存储区中分配一个长度为size的连续空间。当函数申请内存分配成功时,
此函数的返回值是分配区域的起始地址,或者说,此函数是一个指针型函数,返回的指针指向该分配域的开头位置。
(它返回的是分配得到的内存的首字节地址),如果无法获得符合要求的内存块,malloc函数会返回空指针

size为要申请的空间大小,需要我们手动的去计算,如int *p = (int * )malloc(20*sizeof(int)),如果编译器默认int为4字节存储的话,那么计算结果是80 Byte,一次申请一个80 Byte的连续空间,并将空间基地址强制转换为int类型,赋值给指针p,此时申请的内存值是不确定的。

malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓 空闲链表的功能。

调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。

调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。

于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。如果无法获得符合要求的内存块,malloc函数会返回NULL指针(空指针),因此在调用malloc动态申请内存块时,一定要进行返回值的判断。

#include
#include  


int main(void)
{
  int count, *array; /*count是一个计数器,array是一个整型指针,也可以理解为指向一个整型数组的首地址*/


  if ((array=(int *) malloc(10 * sizeof(int))) == NULL)//把类型强制转换为int 申请内存空间 10个int的空间 
                   //一个int大小是sizeof(int)
  {
    printf("不能成功分配存储空间。");
    exit(1); //强制结束程序
  }


  for (count = 0; count < 10; count++) { /*给数组赋值*/
    array[count] = count;
  }


  for (count = 0; count < 10; count++) { /*打印数组元素*/
    printf("%2d", array[count]);
  }
  return 0;


}

free函数:

free()是C语言中释放内存空间的函数,通常与申请内存空间的函数malloc()结合使用,可以释放由 malloc()、calloc()、realloc() 等函数申请的内存空间。

函数原型:

void free(void *ptr);
ptr-- 指针指向一个要释放内存的内存块,该内存块之前是通过调用 
malloc、calloc 或 realloc 进行分配内存的。如果传递的参数是一个空指针,则不会执行任何动作。
该函数不返回任何值。

上面的例子:

#include
#include  


int main(void)
{
  int count, *array; /*count是一个计数器,array是一个整型指针,也可以理解为指向一个整型数组的首地址*/


  if ((array=(int *) malloc(10 * sizeof(int))) == NULL)//把类型强制转换为int 申请内存空间 10个int的空间 
                              //一个int大小是sizeof(int)
  {
    printf("不能成功分配存储空间。");
    exit(1); //强制结束程序
  }


  for (count = 0; count < 10; count++) { /*给数组赋值*/
    array[count] = count;
  }


  for (count = 0; count < 10; count++) { /*打印数组元素*/
    printf("%2d", array[count]);
  }
  
  free(array);  //刚刚没有进行释放内存


  return 0;


}


******free的重要性:*******


静态内存的数量在编译时是固定的,在运行期间也不会改变,
自动变量使用的内存数量在程序执行期间自动增加或减少,但是动态内存分配内存的数量只会增加,除非使用free函数进行释放


它创建了指针array,并调用了malloc函数进行内存分配了(10* 4(int) )40个字节的内存,假设,如代码注释所示,
遗漏了free,当函数结束时,作为自动变量的指针array也会消失,但是它所指向的40个字节的内存却仍然存在,
由于array指针已被销毁,所以无法访问这块内存,它也不能被重复使用,因为代码中没有调用free函数释放这块内存,
如果是一个函数,当第二次调用它时,它又创建了array指针,并调用malloc分配40个字节的内存,第一次调用的40个字节的内存已不可用,
所以malloc函数分配了另外的内存,当函数结束时该内存也无法被访问和再使用,如果循环要进行1000次,那么每一次的调用都会分配内存,
持续增加,实际上,等不到程序结束,内存早已被耗尽,这类问题被称为内存泄漏,所以 为防止这类问题的发生,
必须要在动态内存分配函数后加上free函数释放内存。

总结:

malloc 必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针。另外有一点不能直接看出的区别是,malloc 只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的

一般使用后要使用free(起始地址的指针) 对内存进行释放,不然内存申请过多会导致内存泄漏会影响计算机的性能,以至于得重启电脑。如果使用过后不清零,还可以使用该指针对该块内存进行访问。

通常,malloc函数要和free函数一起配对使用,free函数的参数是之前mallloc函数返回的地址(指针),该函数释放之前malloc函数分配的内存,因此,动态内存分配的存储期是从动态内存分配函数malloc(或其他)到f调用ree函数释放内存为止,涉嫌malloc和free函数管理着一个内存池。

每次调用malloc分配内存给程序使用,每次调用free函数把内存空间归还给内存池中,这样便可以重复使用这些内存,free函数的参数应该是一个指针,指向由malloc函数分配的一块内存,不能用free函数释放通过其他方式(如 :声明一个数组),分配的内存,malloc函数和free函数的原型都在stdio.h头文件中。

审核编辑:郭婷


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储器
    +关注

    关注

    39

    文章

    7769

    浏览量

    172435
  • 函数
    +关注

    关注

    3

    文章

    4423

    浏览量

    68038

原文标题:【零基础学C语言】内存知识总结:realloc函数和free函数

文章出处:【微信号:cyuyanxuexi,微信公众号:C语言编程学习基地】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    请问CW32F030的硬件注意事项有哪些?

    CW32F030的硬件注意事项有哪些
    发表于 12-25 08:20

    请问IAP功能升级流程中有哪些注意事项

    IAP 功能升级流程中有哪些注意事项
    发表于 12-23 07:55

    BNC转接头接线注意事项

    本文从工程角度总结BNC转接头接线过程中的关键注意事项,涵盖阻抗匹配、接线规范、工艺选择及检测要点,帮助用户避免常见接线问题。
    的头像 发表于 12-19 14:04 719次阅读
    BNC转接头接线<b class='flag-5'>注意事项</b>

    迅为RK3588开发板Android系统烧写及注意事项

    迅为RK3588开发板Android系统烧写及注意事项
    的头像 发表于 12-03 15:17 7541次阅读
    迅为RK3588开发板Android系统烧写及<b class='flag-5'>注意事项</b>

    驱动板PCB布线的注意事项

    PCB Layout 注意事项 1)布局注意事项: ●● 整体布局遵循功率回路与小信号控制回路分开布局原则,功率部分和控制部分的 GND 分开回流到输入 GND。 ●● 芯片的放置方向优先考虑驱动
    发表于 12-02 07:40

    Enclustra瑞苏盈科产品使用注意事项

    我们准备了关于瑞苏盈科产品使用的注意事项,旨在帮助客户更快,更好的使用瑞苏盈科的产品,实现以最小化的成本提供理想的解决方案,帮助客户打造独树一帜的产品并减少上市时间。瑞苏盈科核心板使用注意事项:电子
    的头像 发表于 11-28 10:28 893次阅读
    Enclustra瑞苏盈科产品使用<b class='flag-5'>注意事项</b>

    芯源的MCU使用电池过程中有哪些注意事项

    目前大多数MCU都是用电池进行供电,芯源的MCU使用电池过程中有哪些注意事项?应该如何设计电池供电呢?
    发表于 11-20 07:24

    CW32F030在使用中的注意事项有哪些?

    CW32F030在使用中的注意事项有哪些?
    发表于 11-18 06:20

    信号调理设备的接地和环境适配有哪些注意事项

    信号调理设备的接地和环境适配,核心是“阻断干扰传导、适应场景特性”—— 接地不当会引入电磁干扰,环境适配不足会导致器件参数漂移,两者都会直接破坏暂态信号的完整性,让分辨率提升失效。具体注意事项
    的头像 发表于 11-14 16:15 4055次阅读
    信号调理设备的接地和环境适配有哪些<b class='flag-5'>注意事项</b>?

    L083最低功耗是多少,应该如何进行低功耗设计?有哪些注意事项

    L083最低功耗是多少,应该如何进行低功耗设计?有哪些注意事项
    发表于 11-12 07:29

    emWin AppWizard 开发注意事项有哪些?

    emWin AppWizard 开发注意事项
    发表于 09-04 06:18

    别让这些细节毁了PCBA!焊接注意事项清单

    一站式PCBA加工厂家今天为大家讲讲PCBA加工中电子元器件焊接注意事项有哪些?PCBA加工中电子元器件焊接注意事项。 电子元器件焊接关键注意事项 在PCBA加工中,焊接工艺直接影响电路板的可靠性
    的头像 发表于 07-23 09:26 1601次阅读

    智多晶PLL使用注意事项

    在FPGA设计中,PLL(锁相环)模块作为核心时钟管理单元,通过灵活的倍频、分频和相位调整功能,为系统提供多路高精度时钟信号。它不仅解决了时序同步问题,还能有效消除时钟偏移,提升系统稳定性。本文将深入探讨智多晶PLL在实际应用中的关键注意事项,帮助工程师规避常见设计风险。
    的头像 发表于 06-13 16:37 1851次阅读
    智多晶PLL使用<b class='flag-5'>注意事项</b>

    CCG2 type-c to DP 在layout时的注意事项是什么,差分线阻抗多少欧?

    我想问下CCG2type-c to DP 在layout时的注意事项是什么,差分线阻抗多少欧。
    发表于 05-30 07:23

    迅为RK3568驱动指南GPIO子系统 GPIO操作函数实验

    迅为电子RK3568开发板驱动指南GPIO子系统 GPIO操作函数实验
    的头像 发表于 05-28 15:24 1616次阅读
    迅为RK3568驱动指南GPIO子系统 GPIO操作<b class='flag-5'>函数</b><b class='flag-5'>实验</b>