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头文件中。

审核编辑:郭婷


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

    关注

    38

    文章

    7425

    浏览量

    163505
  • 函数
    +关注

    关注

    3

    文章

    4276

    浏览量

    62316

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

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

收藏 人收藏

    评论

    相关推荐

    绕线电感定制的注意事项

    电子发烧友网站提供《绕线电感定制的注意事项.docx》资料免费下载
    发表于 09-20 11:24 0次下载

    LiFePO4设计注意事项

    电子发烧友网站提供《LiFePO4设计注意事项.pdf》资料免费下载
    发表于 09-03 09:24 0次下载
    LiFePO4设计<b class='flag-5'>注意事项</b>

    函数信号发生器怎么调频率

    函数信号发生器是一种常用的电子测试设备,它能够产生各种波形、频率和幅度的信号,广泛应用于科研、教学、生产和维修等领域。在使用函数信号发生器时,调整频率是其中一个非常重要的步骤。本文将详细介绍函数信号发生器如何调整频率,以及相关的
    的头像 发表于 05-20 18:23 1359次阅读

    函数发生器的使用方法和注意事项

    函数发生器,作为电子测试和测量领域的重要工具,广泛应用于生产测试、仪器维修、实验室研究以及通讯等多个科技领域。它的主要功能是产生各种波形、频率和幅度的信号,以满足不同的测试需求。本文将详细介绍函数发生器的使用方法及
    的头像 发表于 05-15 11:44 1490次阅读

    FMD LINK 使用注意事项

    电子发烧友网站提供《FMD LINK 使用注意事项.pdf》资料免费下载
    发表于 05-06 10:11 0次下载

    函数多层调用的主要注意事项分析

    应用方案设计中,开发者经常会碰到某个子函数需要多次多级调用的情况。
    的头像 发表于 03-27 15:36 642次阅读
    子<b class='flag-5'>函数</b>多层调用的主要<b class='flag-5'>注意事项</b>分析

    浪涌抑制器的应用及注意事项

    浪涌抑制器的应用及注意事项?|深圳比创达电子
    的头像 发表于 01-19 09:55 650次阅读
    浪涌抑制器的应用及<b class='flag-5'>注意事项</b>?

    测速电机: 常见6大注意事项

    测速电机: 常见6大注意事项!测速电机是一种用于测量物体运动速度的设备,广泛应用于工业生产和科学研究中。测速电机常见的6大注意事项以确保安全和准确性。
    的头像 发表于 01-11 10:53 414次阅读
    测速电机: 常见6大<b class='flag-5'>注意事项</b>

    霍尔元件使用的注意事项

    霍尔元件使用的注意事项  霍尔元件是一种常见的电子元件,主要用于测量和检测磁场的变化。它具有灵敏度高、响应速度快、耐磁场干扰等优点,在各种应用中得到广泛使用。然而,为了确保霍尔元件的正常工作和延长其
    的头像 发表于 12-18 14:56 1168次阅读

    电流互感器的使用注意事项

    当谈到电流互感器的使用时,有一些重要的注意事项需要我们牢记。在本文中,我们将探讨这些注意事项,为您提供详细和全面的信息。
    的头像 发表于 12-15 10:34 1295次阅读
    电流互感器的使用<b class='flag-5'>注意事项</b>

    if函数三个条件怎么填

    各个条件的使用方法和注意事项。 一、IF函数的基本语法 首先,我们需要了解IF函数的基本语法。IF函数的基本语法为: =IF(逻辑测试, 返回结果为真时的值, 返回结果为假时的值) 其
    的头像 发表于 12-03 10:28 3401次阅读

    wps的vlookup函数的使用方法及实例

    用途和示范。 VLOOKUP函数是一种广泛应用于数据表格和数据库中的函数,用于查找指定的值,并返回与其相关的其他相关值。我们将从以下几个方面介绍VLOOKUP函数的用法:函数语法、参数
    的头像 发表于 12-01 10:58 3670次阅读

    if函数如何嵌套计算公式

    嵌套if函数可以在Excel等电子表格软件中实现复杂的条件判断和计算公式。本文将详细介绍if函数的嵌套使用方法,包括语法、常见应用场景和实例演示等,以及注意事项和进阶技巧。 一、if函数
    的头像 发表于 11-30 16:55 6239次阅读

    VGA OUT 的PCB设计注意事项

    VGA OUT 的PCB设计注意事项
    的头像 发表于 11-23 09:04 775次阅读

    range()函数的用法是什么

    说明: start:序列的起始值,默认为0(可省略)。 stop:序列的结束值(不包含在序列内)。 step:序列中的元素间隔,默认为1(可省略)。 下面我们详细介绍range()函数的使用方法和相关注意事项
    的头像 发表于 11-21 14:46 3652次阅读