C语言中的内存动态管理

1.为什么有动态内存管理

int a=20;//开辟4个字节

int arr[10]={0};//开辟40个字节

上述的代码有两个特点

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

2.数组在申明的时候已经固定了大小,无法更改。

 这样写代码不够灵活,所以c语言中引入了动态内存管理,让程序员可以自己申请和释放空间,这样可以灵活一点。

2.malloc和free

malloc和free的头文件均为stdlib.h

2.1malloc

一个动态内存开辟函数

void*malloc (size_t size)

malloc可以申请一片连续的空间,并返回开辟空间的首地址 

1.开辟成功,返回这片连续空间的首地址。

2.开辟失败,返回NULL指针。例:INT_MAX

3.返回类型是void*,所以开辟空间的类型可以根据使用者自由决定。

4.size是字节数。

2.2free

free是用来释放和回收动态内存管理开辟的空间的。

void free void*ptr)

1.如果ptr指向的空间不是动态开辟的,那么free的行为是未定义的

2.如果ptr是NULL,则函数什么都不做。

#include <stdio.h>
#include<stdlib.h>
int main()
{int* ptr = NULL;ptr = (int*)malloc(10 * sizeof(int));//开辟空间if (NULL != ptr)//判断ptr指针是否为空{int i = 0;for (i = 0; i < 10; i++){*(ptr + i) = 0;}}free(ptr);//释放ptr所指向的动态内存ptr = NULL;return 0;
}

3.calloc和realloc 

3.1calloc

calloc也可以来开辟空间。

void* calloc (size_t num, size_t size);

calloc的功能为开辟num个大小为size的一块空间,并且把空间的每个字节都初始化为0.

 int main()
{
    //申请10个连续的整形空间;
    //malloc(10*sizeof(int))
    int* p = (int*)calloc(10, sizeof(int));
    if (p == NULL)
    {
        perror("calloc");
        return 1;
    }
    //使用
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", p[i]);//打印出10个0。
    }

    //释放
    free(p);
    p = NULL;
    return 0;
}

 calloc和malloc没什么区别,只是calloc会把申请的字节都初始化为0.

3.2realloc

这个函数可以使我们开辟后的空间可以改变。

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

 ptr:要调整的内存地址

size:把该地址改为多大的空间

返回值为改变之后的起始地址

realloc函数在扩容空间的时候,扩容成功有两种情况

情况1.后面有充足的空间,把后面的空间直接分配给你。

情况2.后面的空间不足

1.直接在堆区找一块新的满足大小的空间

2.将旧的数据,拷贝到新的地址当中

3.将旧空间释放

4.返回新的地址

int main()
{//申请10个连续的整形空间;//malloc(10*sizeof(int))int* p = (int*)calloc(10, sizeof(int));if (p == NULL){perror("calloc");return 1;}//使用for (int i = 0; i < 10; i++){printf("%d ", p[i]);}//调整为20个整形空间//用新的指针接收,这样开辟失败也不会丢失p指向的内容int* ptr = (int*)realloc(p, 20 * sizeof(int));if (ptr != NULL){p = ptr;}//使用//。。。//释放free(p);p = NULL;return 0;
}

4.常见的动态内存的错误

4.1对NULL指针的解引用操作

就是没有开辟成功空间,返回NULL地址,又去解引用它。

int main()
{
    int* p = (int*)malloc(sizeof(INT_MAX));
    //使用
    *p = 10;
    //释放
    free(p);
    p = NULL;
    return 0;
}

4.2 对动态开辟空间的越界访问 

int main()
{
    //申请10个连续的整形空间;
    //malloc(10*sizeof(int))
    int* p = (int*)malloc(10*sizeof(int));
    if (p == NULL)
    {
        perror("malloc");
        return 1;
    }
    //使用
    for (int i = 0; i < 40; i++)
    {
        p[i] = i + 1;//越界访问
    }
    free(p);
    p = NULL;
    return 0;
}

 4.3 对非动态开辟内存使用free释放

int main()
{
    int a = 10;
    int* p = &a;
    free(p);
}

free释放的是动态内存的空间。

4.4 使用free释放一块动态开辟内存的一部分 

int main()
{
    //申请10个连续的整形空间;
    //malloc(10*sizeof(int))
    int* p = (int*)malloc(10*sizeof(int));
    if (p == NULL)
    {
        perror("malloc");
        return 1;
    }
    //使用
    for (int i = 0; i < 5; i++)
    {
        *(p++) = i + 1;
    }
    free(p);
    p = NULL;
    return 0;
}

 p的地址被改变了,释放的是一部分

4.5 对同一块动态内存多次释放

int main()
{
    //申请10个连续的整形空间;
    //malloc(10*sizeof(int))
    int* p = (int*)malloc(10 * sizeof(int));
    if (p == NULL)
    {
        perror("malloc");
        return 1;
    }
    //使用
    for (int i = 0; i < 5; i++)
    {
        *(p++) = i + 1;
    }
    free(p);//第一次
    //...
    free(p);//第二次
    p = NULL;
    return 0;
}

p释放了两次,第二次相当于释放野指针了,会发生错误。如果第一次释放p之后把它置为NULL,则不会发生错误,就是逻辑上说不通。

4.6 动态开辟内存忘记释放(内存泄漏 )

void test()
{
    int* p = (int*)malloc(10 * sizeof(int));
    int flag = 1;
    if (p == NULL)
    {
        perror("malloc");
        return 0;
    }
    //使用...


    if (flag)
    {
        return 1;
    }
    free(p);
    p = NULL;
}
int main()
{
    test();
    return 0;
}

这个test函数就没有释放,提前return了

5.动态内存笔试题分析 

5.1对NULL解引用

void GetMemory(char* p)
{
    p = (char*)malloc(100);//p开辟了一片空间,但是和str没有关系

    //忘记free
}
void Test(void)
{
    char* str = NULL;
    GetMemory(str);//传值调用,非传址调用
    strcpy(str, "hello world");//对str进行解引用操作,程序会奔溃
    printf(str);//这个打印是没有问题的
}
int main()
{
    Test();
    return 0;
}

 这个代码有两个错误

1.对str进行解引用操作,程序会奔溃

2.开辟的空间没有释放,内存会泄露

正确写法1

void GetMemory(char** p)
{
    *p = (char*)malloc(100);
}
void Test(void)
{
    char* str = NULL;
    GetMemory(&str);
    strcpy(str, "hello world");
    printf(str);
    free(str);
    str = NULL;
}
int main()
{
    Test();
    return 0;
}

正确写法2

char* GetMemory(char* p)
{
    *p = (char*)malloc(100);
    return p;
}
void Test(void)
{
    char* str = NULL;
    str=GetMemory(&str);
    strcpy(str, "hello world");
    printf(str);
    free(str);
    str = NULL;
}
int main()
{
    Test();
    return 0;

开辟的空间可以返回地址 

5.2返回栈空间地址的问题

char* GetMemory(void)
{
    char p[] = "hello world";
    return p;//返回指针,但是返回之后这个函数就销毁了,但是如果malloc开辟的空间就不会销毁,因为malloc释放的话得用free。
}
void Test(void)
{
    char* str = NULL;
    str = GetMemory();//str接收的是野指针,GetMemory不属于当前程序了
    printf(str);//打印的时候可能被别人修改了
}
int main()
{
    Test();

    return 0;
}

返回栈空间的时候,接收变量没有问题,但是接收地址有问题 ,因为会销毁。

 5.3 注意内存泄漏

void GetMemory(char** p, int num)
{
    *p = (char*)malloc(num);
}
void Test(void)
{
    char* str = NULL;
    GetMemory(&str, 100);
    strcpy(str, "hello");
    printf(str);//可以打印,但是malloc开辟的内存需要释放
}
int main()
{
    Test();
    return 0;
}

正确写法

void GetMemory(char** p, int num)
{
    *p = (char*)malloc(num);
}
void Test(void)
{
    char* str = NULL;
    GetMemory(&str, 100);
    strcpy(str, "hello");
    printf(str);

    free(str);

    str=NULL;
}
int main()
{
    Test();
    return 0;

 5.4非法访问

void Test(void)
{
    char* str = (char*)malloc(100);
    strcpy(str, "hello");
    free(str);//把malloc出来的空间还给操作系统,无法继续使用,str变为野指针
    if (str != NULL)//ok
    {
        strcpy(str, "world");//非法访问
        printf(str);
    }
}
int main()
{
    Test();
    return 0;
}

正确写法

void Test(void)
{
    char* str = (char*)malloc(100);
    strcpy(str, "hello");
    free(str);

    str=NULL;
    if (str != NULL)
    {
        strcpy(str, "world");
        printf(str);
    }
}
int main()
{
    Test();
    return 0;

 6.柔性数组

6.1什么是柔性数组

1.在结构体中

2.最后一个成员

3.未知大小的数组

例如:

struct S
{
    int a;
    char n;
    double b;
    int arr[];//未知大小的数组,arr就是柔性数组成员
};

或者

struct S
{
    int a;
    char n;
    double b;
    int arr[0];//未知大小的数组,arr就是柔性数组成员
}; 

6.2柔性数组的特点

1.结构中的柔性数组成员前面必须至少一个其他成员。
2.sizeof 返回的这种结构大小不包括柔性数组的内存。
3.包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

 struct S
{
    int a;
    int arr[];
};
int main()
{
    printf("%zd", sizeof(struct S));//结果为4
    return 0;
}

 struct S
{
    int a;
    int arr[];
};
int main()
{
    struct S*ps=(struct S*)malloc(sizeof(struct S) + 20 * sizeof(int));
    if (ps == NULL)
    {
        perror("malloc");
        return 1;
    }

    free(ps);

    ps=NULL;

    return 0;

}

6.3柔性数组的使用 

struct S
{
    int a;
    int arr[];
};
int main()
{
    struct S*ps=(struct S*)malloc(sizeof(struct S) + 20 * sizeof(int));
    if (ps == NULL)
    {
        perror("malloc()");
        return 1;
    }
    //使用这片空间
    ps->a = 20;
    for (int i = 0; i < 20; i++)
    {
        ps->arr[i] = i + 1;
    }

    free(ps);

    ps=NULL;
    return 0;
}

6.4柔性数组的大小改变 

struct S
{
    int a;
    int arr[];
};
int main()
{
    struct S* ps = (struct S*)malloc(sizeof(struct S) + 20 * sizeof(int));
    if (ps == NULL)
    {
        perror("malloc()");
        return 1;
    }
    //使用这片空间
    ps->a = 20;
    for (int i = 0; i < 20; i++)
    {
        ps->arr[i] = i + 1;
    }
    //改变柔性数组的大小
    struct S* p = (struct S*)realloc(ps, (sizeof(struct S) + 40 * sizeof(int)));
    if (p != NULL)
    {
        ps = p;
        p = NULL;
    }

    else
    {
    perror("malloc");
    return 1;
    }
    for (int i = 0; i < 40; i++)
    {
        printf("%d ", ps->arr[i]);
    }
    free(ps);
    ps = NULL;
    return 0;
}

 或者

struct S
{
    int a;
    int* arr;
};
int main()
{
    struct S* ps = (struct S*)malloc(sizeof(struct S));
    if (ps == NULL)
    {
        perror("malloc");
        return 1;
    }
    int* tmp = (int*)malloc(20 * sizeof(int));
    if (tmp != NULL)
    {
        ps->arr=tmp;

    }
    else
    {
        perror("malloc");
        return 1;
    }
    //给arr中的数赋值为1~20
    for (int i = 0; i < 20; i++)
    {
        ps->arr[i] = i + 1;
    }
    //修改arr的大小
    tmp=(int *)realloc(ps->arr, 40 * sizeof(int));
    if (tmp != NULL)
    {
        ps->arr = tmp;
    }
    else
    {
        perror("malloc");
        return 1;
    }
    for (int i = 0; i < 40; i++)
    {
        printf("%d ", ps->arr[i]);
    }
    //释放,先释放ps里面的arr,再释放ps
    free(ps->arr);
    ps->arr = NULL;
    free(ps);
    ps = NULL;
    return 0;
}

代码1和代码2均能实现同样的功能,但代码1更好一些,因为代码1malloc的次数少,减少的内存碎片,因为malloc开辟的空间是连续的,开辟的多中间空的间隙也多。

7,总结c/c++中程序内存区域划分

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

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

相关文章

Springboot整合Kafka消息队列服务实例

一、Kafka相关概念 1、关于Kafka的描述 Kafka是由Apache开源&#xff0c;具有分布式、分区的、多副本的、多订阅者&#xff0c;基于Zookeeper协调的分布式处理平台&#xff0c;由Scala和Java语言编写。通常用来搜集用户在应用服务中产生的动作日志数据&#xff0c;并高速的处…

Milvus 2.4 向量库安装部署

1、linux 已有docker环境 2、安装fio命令 yum install -y fio 2、mkdir test-data fio --rwwrite --ioenginesync --fdatasync1 --directorytest-data --size2200m --bs2300 --namemytest ctrlc 3、lscpu 4、docker -v 6、安装docker compose组件 yum -y install python3-…

Maven下载安装、环境配置(超详细)(包括Windows、IDEA)

目录 一、引言 二、下载和安装 Maven &#xff08;1&#xff09;首先保证 Java 的环境是正常的。 1、电脑桌面上右击 " 此电脑 "&#xff0c;点击属性。 2、点击高级系统设置。 3、点击环境变量。 4、找到系统变量中的 Path。 5、点击新建&#xff0c;然后把…

深度剖析ElasticSearch分页原理与深分页问题|ES深分页问题|ES分页原理剖析

文章目录 ES分页|Paginate search resultsES深分页的问题一页获取数据量太大&#xff0c;报错分页深度太大&#xff0c;报错官方解释 其他解决方案Search after解决两个问题 有没有深分页查询的必要性&#xff1f;search after & PIT的使用方式1.创建pit2.首次查询3.之后的…

【C++】#20,#21

#20类和对象 #include <iostream>using namespace std;class Box{public: //公有 double length; //ctrle复制本行 double width;double height;void getVolume(){ //方法带&#xff08;&#xff09; cout<<"盒子体积为&#xff1a;"<<le…

我在高职教STM32——LCD液晶显示(1)

大家好&#xff0c;我是老耿&#xff0c;高职青椒一枚&#xff0c;一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次&#xff0c;同行应该都懂的&#xff0c;老师在课堂上教学几乎是没什么成就感的。正因如此&#xff0c;才有了借助 CSDN 平台寻求认同感和成就…

十、数据结构(图的基础)

文章目录 什么是图图的分类图算法的复杂度 图的模拟怎么储存一个图邻接矩阵&#xff1a;邻接矩阵的定义方式优劣分析 邻接表优劣分析实现代码 链式前向星实现代码优劣分析 图的遍历某个点的连通性拓扑排序1.拓扑排序的概念2.图的入度和出度3.基于 B F S BFS BFS的拓扑排序复杂度…

uniapp公用返回组件

uniapp写一个公用的头部组件&#xff0c;包含home和返回。 页面中的引用 2.在components文件夹下&#xff0c;新建一个navBar.vue <template><view class"view-wrap"><view :style"{ height: barHeight }"></view><view cla…

web前端之vue一键部署的shell脚本和它的点.bat文件、海螺AI、ChatGPT

MENU 前言vite.config.ts的配置deploy文件夹的其他内容remote.shpwd.txtdeploy.bat 前言 1、在src同级新建deploy.bat文件&#xff1b; 2、在src同级新建deploy文件夹&#xff0c;文件夹中新建pwd.txt和remote.sh文件&#xff1b; 3、配置好后&#xff0c;直接双击deploy.bat文…

Flat Ads:轻松玩转Kwai广告,开启全球营销新篇章

在当今数字化时代,短视频平台已成为人们生活中不可或缺的一部分。其中,快手旗下的一款海外短视频应用——Kwai 在海外新兴的拉美、中东、东南亚等多个市场迅速崛起并赢得了广大用户的喜爱。 作为全球头部短视频平台,Kwai 已遍布世界30多个国家,月活超过10亿,APP下载量位居拉美、…

怎么给软件做数字证书签名?

要想让软件获得身份并让计算机识别软件发布者就需要申请数字证书&#xff0c;CA机构严格实名认证后签发的数字证书就可以对指定的软件签名使用。 代码签名是使用数字证书对软件、固件、脚本和可执行文件进行签名的过程&#xff0c;旨在向最终用户和客户保证代码的完整性和真实…

【深度学习驱动流体力学】剖析流体力学可视化paraview原理

目录 1.paraview版本2.配置过程检查插件库文件配置 ParaView 环境变量启动 ParaView 并检查插件3.可视化测试插件功能 3.加载数据进行可视化第一步: 导入案例第二步:查看当前目录未更新前的内容第三步:使用 blockMesh 命令生成腔体案例的网格第四步:运行仿真icoFoam第五步:使用…

短剧APP开发,探索短剧市场的新机遇

近几年&#xff0c;短剧市场得到了繁荣发展&#xff0c;随着短剧的快速发展&#xff0c;短剧APP也得到发展&#xff0c;受到了越来越多用户的喜欢。通过短剧APP&#xff0c;为大众带来多样、高质量的短剧内容。对于影视创作者来说&#xff0c;短剧APP在线观看系统的开发也将成为…

安装ps提示vcruntime140.dll丢失的多种有效的解决方法分享

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到vcruntime140.dll”。这个错误通常出现在运行某些程序时&#xff0c;特别是ps这样的图像处理软件。那么&#xff0c;如何解决这个错误呢&#xff1f;小编将为您详细介绍打开提示ps找…

【车载音视频AI电脑】全国产海事船载视频监控系统解决方案

海事船载视频监控系统解决方案针对我国快速发展的内河航运、沿海航运和远洋航运中存在的航行安全和航运监管难题&#xff0c;为船舶运营方、政府监管部门提供一套集视频采集、存储、回放调阅为一体的视频监控系统&#xff0c;对中大型船舶运行中的内部重要部位情况和外部环境进…

Windows的hosts文件中配置域名——在host文件中添加域名与IP的映射关系

Windows配置域名解析——在hosts文件中添加映射关系 要配置域名解析&#xff0c;步骤如下&#xff1a; 首先选中Windows的hosts文件——即C:\Windows\System32\drivers\etc&#xff0c;右键属性&#xff0c;在属性对话框中选中“安全”选项卡&#xff0c;点击“编辑”按钮&…

甘特图如何画以及具体实例详解

甘特图如何画以及具体实例详解 甘特图是一种常见的项目管理工具又称为横道图、条状图(Bar chart)。是每一位项目经理和PMO必须掌握的项目管理工具。甘特图通过条状图来显示项目、进度和其他时间相关的系统进展的内在关系随着时间进展的情况。但是多项目经理和PMO虽然考了各种证…

Maya 白膜渲染简单教程

零基础渲染小白&#xff0c;没关系&#xff0c;一篇超简单教程带你学会渲染白膜。 先打开Maya&#xff0c;看看面板有没有渲染器&#xff0c;这里以Arnold为主。 要是没有这个&#xff0c;就去找插件管理器&#xff0c; Arnold的是mtoa&#xff0c;在搜索栏搜&#xff0c;然后把…

未来科技:Web3如何重塑物联网生态系统

随着Web3技术的崛起&#xff0c;物联网&#xff08;IoT&#xff09;的发展正迎来一场深刻的变革。本文将深入探讨Web3如何重塑物联网生态系统&#xff0c;从技术原理到应用实例&#xff0c;全面解析其对未来科技发展的影响和潜力。 1. Web3技术简介与发展背景 Web3技术是建立在…

用小频谱仪观察收音机的本振

我找了一颗中周&#xff0c;想搭建一个几百khz的振荡电路&#xff0c;类似中波的本振&#xff0c;但是搭建了却看不到任何起振的波形。 遂想先看看已经装调好的中波收音机的本质波形是怎么样的&#xff1f; 用杜邦线加上一个夹子。把线夹到小频谱的天线杆上面。 取信号位置可…