【C语言进阶:动态内存管理】动态内存函数的介绍

news2025/6/21 6:39:03

本节重点内容:

  • malloc 和 free 函数
  • calloc 函数
  • realloc 函数

🌸为什么存在动态内存分配

到目前为止,我们已经掌握的内存开辟方式有两种:

  • 创建变量:

int val = 20;        //在栈空间上开辟四个字节

  • 创建数组:

char arr[10] = {0};         //在栈空间上开辟10个字节的连续空间

上述的开辟空间的方式有两个特点:

  1.  空间开辟大小是固定的。
  2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。

但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。

这两种内存开辟的方法创建的空间大小是固定的,不能发生变化,因此就存在一定的局限性。C语言为了让我们更加灵活容易的控制我们所需的内存空间的大小,提供了动态内存管理的功能,也相应地提供了一些动态内存管理的函数。那这篇博客将带着大家来认识这些函数。


⚡malloc 和 free 函数

C语言提供了一个动态内存开辟的函数:

 这个函数向内存申请一块连续可用的空间(字节),并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
  • 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。

C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收的:

 free函数用来释放动态开辟的内存,参数是开辟内存的起始位置。

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数 ptr 是NULL指针,则函数什么事都不做。

malloc 和 free 都声明在 stdlib.h 头文件中。

malloc 和 free 函数的基本使用:

申请20个字节的内存空间来存放整形

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>

int main()
{
    int* p = (int*)malloc(20);   // 由于要存储的为整形,使用int* 的指针来管理比较方便
                                 // malloc的返回值为void*,想要将其赋给int* 的指针,必须进行强 
                                 // 制类型转化
    // malloc 函数也是有可能开辟空间失败的,一般都会对malloc函数的返回值进行判断
    if (p == NULL)
    {
        printf("%s\n", strerror(errno));
    }

    //使用
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        *(p + i) = i + 1;
        printf("%d ", *(p + i));
    }
    //需要对主动申请的空间需要进行主动释放
    free(p);
    //虽然已经释放了p指向的内存,但p还是指向地址没有发生变化,为了避免野指针,应该将p置空
    p = NULL;  
}

运行结果如下:


⚡calloc 函数

malloc函数在初始化时会将每个字节赋一个随机值:

因此C语言还提供了一个函数叫 calloc , calloc 函数也用来动态内存分配:

  • 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
  • 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。

calloc 函数的基本使用:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
    int* p = (int*)calloc(10,sizeof(int));   // 开辟10个整形的空间
    if (p == NULL)
    {
        printf("calloc() --> %s\n", strerror(errno));
    }
    //使用
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        printf("%d ", *(p + i));
    }
    //释放
    free(p);
    p = NULL;
    return 0;
}

运行结果如下:

 

 calloc 和 malloc 函数的对比:

  1. 参数不同。
  2. 都是在堆区上申请内存空间,但是 malloc 不初始化,calloc 会初始化为0。如果需要初始化就用 calloc ,不需要就用 malloc 。
  3. 由于 malloc 没有初始化,因此 malloc 效率会比 calloc 高,因此在使用时需要进行决策判断用哪种效果更好。

⚡realloc 函数 

  • realloc函数的出现让动态内存管理更加灵活。
  • 有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。

  • ptr 是要调整的内存地址。
  • size 调整之后新大小。
  • 返回值为调整之后的内存起始位置。
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
  • realloc在调整内存空间的是存在两种情况:
  1. 情况1:原有空间之后有足够大的空间。
  2. 情况2:原有空间之后没有足够大的空间。
     

在实际使用realloc函数时可能会出现以下两种情况:

情况一:realloc 返回的是旧地址要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

在遇到情况二时需要注意一些点: 

  1. 在空间不足时,realloc 会寻找更大的空间。
  2. 将原来的数据拷贝到新的空间。
  3. 释放旧的空间。
  4. 返回新空间的地址。

原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用,这样函数返回的是一个新的内存地址。

realloc 的基本使用:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
    int* p = (int*)malloc(20);
    if (p == NULL)
    {
        printf("%s\n", strerror(errno));
    }
    //使用
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        *(p + i) = i + 1;
    }
    int* ptr = (int*)realloc(p, 40);
    if (ptr != NULL)
    {
        p = ptr;
        for (i = 5; i < 10; i++)
        {
            *(p + i) = i + 1;
        }
        for (i = 0; i < 10; i++)
        {
            printf("%d ", *(p + i));
        }
    }
    else
    {
        printf("realloc --> %s\n", strerror(errno));
    }
    //释放
    free(p);
    p = NULL;
    return 0;
}

 运行结果如下:


感谢大家能够看完这篇博客,创作时长,小伙伴们觉得我的博客对你有帮助,不妨留下你的点赞的收藏,关注我,带你了解不一样的C语言。

98b76a6f4a9c4ca88fd93da1188ac6f9.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/411396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Html5钢琴块游戏制作与分享(音游可玩)

当年一款手机节奏音游&#xff0c;相信不少人都玩过或见过。最近也是将其做了出来分享给大家。 游戏的基本玩法&#xff1a;点击下落的黑色方块&#xff0c;弹奏音乐。&#xff08;下落的速度会越来越快&#xff09; 可以进行试玩&#xff0c;手机玩起来效果会更好些。 点击…

【Python】基于serial的UART串口通信(可实现AT指令自动化 以ML307A开发板为例)

【Python】基于serial的UART串口通信&#xff08;可实现AT指令自动化 以ML307A开发板为例&#xff09; Python下的串口serial库 串行口的属性&#xff1a; name:设备名字 portstr:已废弃&#xff0c;用name代替 port&#xff1a;读或者写端口 baudrate&#xff1a;波特率 byt…

Charles 安装及配置,详细步骤(不错,保存一下)

一、安装激活 1.1、下载 https://www.charlesproxy.com/download/ 1.2、激活 打开Charles > Help > Register Charles > 输入 Registered Name &#xff1a; https://zhile.io License Key&#xff1a;48891cf209c6d32bf4 二、代理配置 2.1、代理设置 Proxy > Pr…

Nodejs中的fs模块

一、文件写入操作 writeFile 直接打开文件默认是 w 模式&#xff0c;所以如果文件存在&#xff0c;该方法写入的内容会覆盖旧的文件内容 语法&#xff1a; writeFile(file, data[, options], callback)异步writeFileSync(file, data)同步 参数&#xff1a; file文件名data要…

MYSQL 2:一条更新语句是如何进行的

一. MYSQL的一条更新语句如何进行的&#xff1f; 和查询一样&#xff0c;一开始我们需要通过连接器连接到MYSQL服务器上&#xff0c;然后我们会将我们的语句交给解析器&#xff0c;然后交给执行器。比如我们执行一条这样的语句 update cc1 from user_info where id 2 1.执行…

PTA:C课程设计(5)

山东大学&#xff08;威海&#xff09;2022级大一下C习题集&#xff08;5&#xff09;函数题5-6-1 求一组数中的平均值及最大值5-6-2 判断满足条件的三位数5-6-3 函数实现字符串逆序5-6-4 查找子串5-6-5 计算最长的字符串长度5-6-6 二分查找编程题5-7-1 找最长的字符串5-7-2 藏…

第七天sql优化篇

一、查询SQL尽量不要使用select *&#xff0c;而是select具体字段 因为select * 进行查询时&#xff0c;很可能就不会使用到覆盖索引了&#xff0c;就会造成回表查询 select stu.name from student stu; 二、如果知道查询结果只有一条或者只要最大/最小一条记录&#xff…

CMMI认证唯一查询官网

CMMI是“能力成熟度模型集成”的意思。是一种评估或者认证制度。最新的CMMI V2.0模型有四个视图&#xff0c;DEV开发视图、SVC服务视图、供应商、人力资源&#xff0c;目前开发视图是全球应用最广泛的&#xff0c;主要是由CMMI研究院主任评估师按照CMMI模型检查企业或组织的软件…

HTML - 实现IE浏览器访问网址自动跳转至谷歌浏览器打开

HTML - 实现IE浏览器访问网址自动跳转至谷歌浏览器打开一. 实现代码二. IE浏览器设置一. 实现代码 注意&#xff1a;代码中的数据变量需要使用 var 声明 核心代码var href "http://www.baidu.com" //创建ActiveXObject实例&#xff0c;只在IE下有效&#xff0c;才可…

TensorFlow详解2原理

一、从helloworld开始 二、Tensorflow编程模式 一般有两种编程模式。 第一种是命令式编程–Torch&#xff0c; 第二种是符号式编程–Tensorflow; tensorflow比torch有相对的一定的优化&#xff1b; 命令式编程实际上是一种最常见的编程模式&#xff0c;因为易于理解而且基本没…

怎么压缩pdf,如何压缩pdf大小,4种高质量办法

怎么压缩pdf&#xff0c;如何压缩pdf大小&#xff0c;如何找到最合适、最高效的方法&#xff0c;是每一个人必须认真对待的问题。那么我们如何能提高工作效率呢&#xff1f;在办公中我们首先就是要先制定工作计划&#xff0c;心中有机会才能合理的安排工作时间&#xff0c;这样…

工业企业清洁运输台账存在的问题及应对措施

按照超低排放政策规定&#xff0c;企业要实现清洁运输超低排放改造&#xff0c;除了提高企业大宗物料和清洁方式运输比例外&#xff0c;同时还要建立清洁运输台账&#xff0c;根据台账等数据资料判断企业清洁运输比例是否满足要求。而目前对于大多数未完成超低排放的企业来说&a…

Nand Flash基础知识

1、Nand Flash组织架构 Device&#xff08;Package&#xff09;就是封装好的nand flash单元&#xff0c;包含了一个或者多个target。一个target包含了一个或者多个LUN&#xff0c;一个target的一个或者多个LUN共享一组数据信号。每个target都由一个ce引脚&#xff08;片选&…

07-vue的组件化

文章目录1.概述存在的问题&#xff1a;那么如何解决这种状况&#xff1a;2.组件化1.基本概述2.优点1.概述 对于前端来说&#xff0c;我们为用户创造价值才是特别需要关注的一个问题&#xff0c;这么多年过去了&#xff0c;前端到底为用户创造了什么价值呢&#xff1f; 70 年代…

Nacos2.2版本Tomcat启动报错

Nacos2.2版本Tomcat启动报错 错误日志 查看 logs/start.out&#xff0c;可以看到报错信息 2023-04-09 19:36:23,081 ERROR Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean wi…

Linux系统上如何禁用 USB 存储

Linux系统上如何禁用 USB 存储 为了保护数据不被泄漏&#xff0c;我们使用软件和硬件防火墙来限制外部未经授权的访问&#xff0c;但是数据泄露也可能发生在内部。 为了消除这种可能性&#xff0c;机构会限制和监测访问互联网&#xff0c;同时禁用 USB 存储设备。 我是艾西&…

手写一个Promise

Promise Promise是一个对象&#xff0c;用于解决异步变成的问题&#xff0c;由传统的异步回调为服务端立即调用优化为使用者者掌握回调主动权。 比如传统的JSONP&#xff0c;如下&#xff0c;在请求路由里添加回调函数&#xff0c;由接收请求的一方来调用请求&#xff0c;使用…

小白学Pytorch系列--Torch.nn API Vision Layers(15)

小白学Pytorch系列–Torch.nn API Vision Layers(15) 方法注释nn.PixelShuffle将形状张量(∗&#xff0c;Cr2,H,W)(*&#xff0c;C r^2,H,W)(∗&#xff0c;Cr2,H,W)中的元素重新排列为形状张量(∗&#xff0c;C,Hr,Wr)(*&#xff0c;C,H r,W r)(∗&#xff0c;C,Hr,Wr)&#x…

详细介绍React路由

路由 单页Web应用&#xff08;single page web application&#xff0c;SPA&#xff09;&#xff0c;整个应用只有一个完整的页面&#xff0c;点击页面中的链接不会刷新页面&#xff0c;只会做页面的局部更新。数据都需要通过ajax请求获取, 并在前端异步展现。 一个路由就是一…

高通SDX12:ProSLIC Si32185移植调试

一、SLIC业务流程图 本次在高通SDX12平台上支持语音芯片Si32185大致流程如下: 驱动部分直接放在Kernel中,通过SPI注册设备创建字符节点,与硬件建立连接注册设备成功并在audio_kernel中正确配置FE、BE后,声卡会创建出来应用层直接放在apps_proc下,通过IOCTL操作驱动层,通…