动态内存管理

简介: 对于使用数组或者是使用变量开辟内存,往往存在以下劣势之处

前言

对于使用数组或者是使用变量开辟内存,往往存在以下劣势之处


1. 空间开辟大小是固定的。


2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。


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


那对于此类问题怎么解决呢,小编就给大家带来今天的主角。


1.动态内存函数的介绍

1.1 malloc函数

malloc的功能是开辟一个连续的动态内存,具体使用和细节如下


void* malloc (size_t size);


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


2.如果开辟成功,则返回一个指向开辟好空间的指针。


3.如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。(需要用if语句判断,再使用strerror函数返回错误信息)


4.返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。


5.如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。(size表示的是多少个字节的内存大小)


使用展示

#include <stdio.h>
#include<stdlib.h>//头文件,使用时记得添加
#include<string.h>//strerror函数使用的头文件
#include<errno.h>//为了使用errno变量
int main()
{
    char* p = (char*)malloc(sizeof(char) * 26);//这里表示开辟一个内存大小为26字节的内存,用指针p指向
    if (p == NULL)//判断malloc函数是否申请成功,如果申请失败,直接结束函数
    {
        printf("%s ",strerror(errno));
        return 1;
    }
    int i = 0;
    for (i = 0; i < 26; i++)
    {
        p[i] = 'A' + i;
    }
    for (i = 0; i < 26; i++)
    {
       printf("%c",p[i]);
    }
    free(p);
    p = NULL;
    return 0;
}

结果展示:

image.png

这里大家可以看到一个新的函数free,这是专门是用来做动态内存的释放和回收的。对于这个函数介绍如下


1.2 free函数

void free (void* ptr);


free函数用来释放动态开辟的内存。,如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。如果参数 ptr 是NULL指针,则函数什么事都不做。(注意:free只能释放动态开辟的空间)

1.2.1 free函数的重要性

对于自动变量,该在内存使用的数量在程序执行期间会自动地增加,减少,但对于动态分配的内存,只会增加,,除非使用free函数进行释放。如果内存不及时释放,会导致内存泄漏,甚至可能导致系统地崩盘。


1.3 calloc函数

calloc函数的使用效果大概一致,但也有一些不同,至于有哪些不同呢?接下来听小编细细道来


void* calloc (size_t num, size_t size);


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


对于返回值: 成功时,指向函数分配的内存块的指针。如果函数无法分配请求的内存块,则返回空指针。(需要用if语句判断,在使用strerror函数返回错误信息),使用后也需要用free释放。


使用展示:


#include <stdio.h>
#include<stdlib.h>//头文件,使用时记得添加
#include<string.h>//strerror函数使用的头文件
#include<errno.h>//为了使用errno变量
int main()
{
    char* p = (char*)calloc(26,sizeof(char));//这里表示开辟一个内存大小为26字节的内存,用指针p指向
    if (p == NULL)//判断malloc函数是否申请成功,如果申请失败,直接结束函数
    {
        printf("%s ", strerror(errno));
        return 1;
    }
    int i = 0;
    for (i = 0; i < 26; i++)
    {
        p[i] = 'A' + i;
    }
    for (i = 0; i < 26; i++)
    {
       printf("%c",p[i]);
    }
    free(p);
    p = NULL;
    return 0;
}

这里我们打开调试看一下calloc申请后内存中的存储内容:


image.png


这里可以看到由calloc申请动态内存空间后,内部被自动初始化为0


运行结果:image.png


1.4  realloc函数

   对于动态内存函数中是否有一个函数具有对动态开辟内存大小的调整的功能呢?这里realloc函数具有的正是这个作用。


void* realloc (void* ptr, size_t size);


这里ptr 是要调整的内存地址,size 指的是调整之后新大小(可以调大也可以调小)(当ptr为空指针时realloc和malloc函数的作用时一致的)


返回值为调整之后的内存起始位置。失败后直接返回空指针。那对于返回的的地址,它是之前动态产生的旧地值呢,还是会返回一个新的地址呢?这里我们需要分情况讨论。


情况1:原有空间之后有足够大的空间


情况2:原有空间之后没有足够大的空间


情况1


当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。


情况2


当是情况2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间,然后把旧的空间的数据拷贝到新空间前面的位置,并且把旧的空间释放掉,同时返回新空间的地址


使用展示:


#include <stdio.h>
#include<stdlib.h>//头文件,使用时记得添加
#include<string.h>//strerror函数使用的头文件
#include<errno.h>//为了使用errno变量
int main()
{
    char* p = (char*)malloc(24 * (sizeof(char)));//这里表示开辟一个内存大小为24字节的内存,用指针p指向
    if (p == NULL)//判断malloc函数是否申请成功,如果申请失败,直接结束函数
    {
        printf("%s ", strerror(errno));
        return 1;
    }
    char* ptr = (char*)realloc(p, 400*sizeof(char));/*这里最好不要使用原指针指向,如果申请失败会导致,原指针指向
                                     空指针,导致内存泄漏
                                    */
    if (ptr != NULL)
    {
        p = ptr;
        ptr = NULL;
    }
    int i = 0;
    for (i = 0; i <26; i++)
    {
        p[i]= 'A' + i;
    }
    for (i = 0; i < 26; i++)
    {
        printf("%c", p[i]);
    }
    free(p);
    p = NULL;
    return 0;
}


结果显示:


image.png

image.png

相关文章
|
机器学习/深度学习 Go 计算机视觉
YOLOv8改进 | Neck篇 | 利用ASF-YOLO改进特征融合层(适用于分割和目标检测)
YOLOv8改进 | Neck篇 | 利用ASF-YOLO改进特征融合层(适用于分割和目标检测)
1010 1
|
消息中间件 运维 Kafka
运维排查 | Systemd 之服务停止后状态为 failed
运维排查 | Systemd 之服务停止后状态为 failed
|
数据安全/隐私保护 iOS开发 MacOS
Mac中使用命令行来加密压缩zip文档
Mac中使用命令行来加密压缩zip文档
436 0
|
机器学习/深度学习 算法 决策智能
【深度学习】遗传算法
【深度学习】遗传算法
|
12月前
|
API 开发者 UED
自学记录鸿蒙API 13:PreviewKit从文件预览到应用开发
通过学习API 13,我深入研究了**PreviewKit(文件预览服务)**。该模块支持快速预览多种文件类型(文本、图片、视频、音频、PDF等),为文件管理类应用提供系统级支持。本文分享了从搭建开发环境到实现单文件和多文件预览的全过程,并介绍了如何构建一个实用的文件预览助手应用。通过实践,不仅掌握了技术细节,还提升了个人开发能力。希望这些经验能为其他开发者带来启发与帮助。
295 10
自学记录鸿蒙API 13:PreviewKit从文件预览到应用开发
|
人工智能 算法 前端开发
阿里通义灵码的最佳实践
上周首次尝试了阿里巴巴的通义灵码AI插件,体验良好。该插件体积适中,约5.8M,适合项目开发使用。其@workspace和@terminal功能强大,能快速帮助开发者熟悉新项目结构,提供智能代码导航、搜索、优化及错误提示等服务,显著提升开发效率与代码质量。实践证明,通义灵码在加速项目理解和新需求实现方面表现出色,是开发者的得力助手。
577 1
阿里通义灵码的最佳实践
|
编解码 数据可视化
基于transform的scale属性,实现数据可视化大屏自适应缩放,保持比例不变,轻松应对不同分辨率
基于transform的scale属性,实现数据可视化大屏自适应缩放,保持比例不变,轻松应对不同分辨率
1126 0
|
XML 缓存 数据库
Discuz! X3.0 版本的数据库字典
Discuz! X3.0 版本的数据库字典
219 0
|
安全 Java 数据库
SpringBoot - 安全入门与SpringSecurity
SpringBoot - 安全入门与SpringSecurity
463 0
|
存储 弹性计算 负载均衡
自己买服务器还是租赁云服务器好?附2024年阿里云云服务器优惠价格表
随着技术的飞速发展,无论是个人还是企业,在面临选择服务器的问题时都会陷入纠结:究竟是自己购买服务器还是租赁云服务器更为合适? 云服务器的灵活性成为其显著优势。想象一下,当您的业务突然迎来爆发式增长,需要更多的计算和存储资源时,云服务器允许您按需购买,随时扩展或缩小规模,轻松应对各种变化。此外,云服务器还能迅速提供负载均衡、CDN等新的应用程序或服务,助力您的业务快速发展。
741 1