【C语言进阶篇】动态内存管理

【C语言进阶篇】动态内存管理

🌈个人主页:开敲

🔥所属专栏:C语言

🌼文章目录🌼

1. 为什么要有动态内存分配

2.动态内存开辟和释放函数

   2.1 动态内存释放函数

      2.1.1 free函数

   2.2 动态内存开辟函数

      2.2.1 malloc函数 

      2.2.2 calloc函数

      2.2.3 realloc函数

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

    3.1 对NULL指针的解引用操作

    3.2 对动态开辟内存的越界访问

    3.3 对非动态开辟的内存free释放

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

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

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

4. 动态内存经典笔试题练习

5. 柔性数组

    5.1 柔性数组的特点

    5.2 柔性数组的使用

    5.3 柔性数组的优势

1. 为什么要有动态内存分配

  在我们之前的学习中,掌握的开辟内存的方式有:

1 int a = 0;//在上开辟四个字节的空间

int arr[10] = {0};//在上开辟10个整型(40个字节)的空间

但是上面这种开辟空间的方法有两个特点:

① 开辟空间的大小是固定的

② 数组在声明的时候,一旦数组的大小确定下来了,在编译时就不能改变

  但在我们实际的情况中,对于空间的需求不仅仅是上述的情况,实际我们可能在编译的时候才能确定所需空间的大小,这个时候上面这写开辟空间的方式就不适用了。这个时候就需要用到我们灵活(动态)地进行内存地开辟。

  C语言引入了动态内存开辟,这使得程序员能够自己根据实际需求来申请释放空间,使代码更加的灵活。

  下面就来介绍几个动态内存开辟的函数和动态内存释放的函数。

2.动态内存开辟和释放函数

  这些函数都声明在头文件<stdlib.h>

   2.1 动态内存释放函数
      2.1.1 free函数

  free函数是动态内存管理中必不可少的十分重要的一个函数,用来将动态开辟的内存释放和回收,函数说明如下:

 ① 如果参数ptr所指向的空间不是动态开辟的,那么free的行为是未定义的

 ② 如果参数ptr是NULL指针,则函数什么事也不干

  函数使用:

   2.2 动态内存开辟函数
      2.2.1 malloc函数 

  这个函数向内存申请一块连续的可用地址,并且返回这块地址的指针。size(需要开辟的空间大小,单位是字节)下面是关于这个函数的一些说明:

   如果开辟成功,则返回一个指向开辟好的空间地址的指针

  如果开辟失败,则返回一个NULL指针。(因此,malloc的返回值必须进行检查)

  ③ 返回指针的类型为void*,因此malloc可以返回一个任意类型的指针,具体类型由使用者决定

  ④ 如果参数size为0,malloc执行的行为是未定义的,具体由编译器决定

  函数使用:

      2.2.2 calloc函数

  calloc函数与malloc函数十分相似,区别在于calloc函数的参数部分多了一个num(需要开辟的元素个数),size(每个元素的大小)并且calloc函数在开辟空间时会将开辟好的空间里的内容初始化为0:

 ​​​​​​​

      2.2.3 realloc函数

  在我们动态开辟内存时,时而会发现申请的空间太小了,时而又会发现申请的空间太大了,那么为了能够合理地使用内存,我们就需要对内存的大小进行调整。realloc函数就可以做到对动态开辟内存大小的调整。

  realloc函数的作用是:将动态开辟的空间扩容。

  ① ptr是要调整的内存的地址

  size是调整之后希望的大小

  ③ 返回的是调整之后的内存起始地址

  ④ 在调整好空间后,将原有空间内已经存放的数据拷贝到新的空间中

   ​​​​​​​realloc在调整内存空间大小时有以下两种情况:

    1. 原有空间后有足够大的空间存放扩容后的空间,直接向后开辟新的空间

    2. 原有空间后没有足够大的空间,则重新找一块可用的足够大的空间进行开辟,然后返回新空间的地址,同时将原有空间的数据拷贝到新的空间中

由于上述两种情况的存在,在使用realloc函数时必须对realloc返回的指针进行是否为NULL指针的检查。

3. 常见的动态内存的错误
  3.1 对NULL指针的解引用操作

  1  void text()

  2   {

  3        int* p = (int*)malloc(INT_MAX);//这里由于需要开辟的空间太大,导致无法正常开辟

  4                                                          //空间,malloc返回一个NULL指针

  5        *p = 20;//这里的p为NULL指针,对NULL指针解引用操作

  6         free(p);

  7   }

    3.2 对动态开辟内存的越界访问

  void text()

2       {

3                int i = 0;

              int* pf = (int*)malloc(10*sizeof(int));

              if(pf==NULL)

6                     {

7                           exit(EIXT_FAILURE);

8                     }     

9                 for(i = 0;i<=10;i++)  //循环次数为11次 

10                   {

11                          *(p+i) = i;

12                   }

13                free(pf);

14                pf = NULL;

15       }          

    3.3 对非动态开辟的内存free释放

1    void text()

2       {

3             int a = 10;

4             int*p = &a;

5             free(p);

6       }

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

1    void text()

2       {

3              int* pf = (int*)malloc(5*sizeof(int));

4              pf++;    //pf不再指向动态开辟内存的起始地址

5              free(p);

6       }

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

1    void text()

2       {

3             int* pf = (int*)malloc(5*sizeof(int));

4             free(p);

5             free(p);

6       }

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

  这是动态内存错误中最严重的一个错误

1    void text()

2        {

3               int* pf = (int*)malloc(5*sizeof(int));

4               if(pf != NULL)

5                     {

6                           *p = 20;

7                      }

8        }

9

10    int main()

11       {

12            text();

13            while(1);//这里再出函数之后直接进入了死循环,函数内也没有释放内存,导致

14                           //开辟的这块空间无法释放,也无法使用,导致内存泄漏

15       }

切记:动态开辟的内存一定要释放,并且正确释放!

4. 动态内存经典笔试题练习

  题目1:

题目2:

题目3:

题目4:

5. 柔性数组

  也许你从来没有听说过柔性数组(flexible array)这个概念,但它确实是存在的。

  C99中,结构体中的最后一个元素是位置大小的数组,这个数组就是柔性数组。例如:

1    typedef struct st_sype

2       {

3              int i = 0;

4              int a[ ];

5       }type_a;

    5.1 柔性数组的特点

   结构体中的柔性数组成员前必须有至少一个其它成员(保证柔性数组是结构体的最后一个成员)

  ② sizeof在计算这种结构体时,不会算入柔性数组的大小

  ③ 包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应当大于sizeof计算结构体的大小,以保证能够满足柔性数组的预期大小。

  例如:

​​​​​​​1       typedef struct st_type
2           {
3               int i;
4               int a[0];//柔性数组成员
5           }type_a;

6
7       int main()
8           {
9              printf("%d\n", sizeof(type_a));//输出的是4
10              return 0;
11          }
 

    5.2 柔性数组的使用

  1  //代码1
  2   #include <stdio.h>
  3   #include <stdlib.h>
  4     int main()
  5        int i = 0;
  6           type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
  7           //业务处理
  8            p->i = 100;
  9            for(i=0; i<100; i++)
  10               {
  11                    p->a[i] = i;
  12               }
  13           free(p);
  14           return 0;
  15        }
 

这样柔性数组成员a相当于获得了100个整型元素的连续空间。

  上述的type_a结构也可以设计为下面的结构,也能完成相同的效果。

//代码2
2     #include <stdio.h>
3     #include <stdlib.h>

4
5      typedef struct st_type
6             {
7                 int i;
8                 int *p_a;
9             }type_a;
10        int main()

11          {

12             type_a *p = (type_a *)malloc(sizeof(type_a));
13              p->i = 100;
14              p->p_a = (int *)malloc(p->i*sizeof(int));
15              //业务处理
16              for(i=0; i<100; i++)
17                   {
18                        p->p_a[i] = i;
19                   }
20               //释放空间
21               free(p->p_a);
22               p->p_a = NULL;
23               free(p);

24               p = NULL;
25               return 0;
26             }
 

    5.3 柔性数组的优势

  上述代码1代码2可以完成相同的功能,但是代码1有两个好处:

  ①:方便内存释放

  如果我们的代码是在⼀个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存⼀次性分配好了,并返回给用户⼀个结构体指针,用户做⼀次free就可以把所有的内存也给释放掉。

  ②:有利于访问速度

  连续的内存有益于提高访问速度以及提高内存的利用率,也有益于减少内存碎片,提高内存的利用率。

                                                  创作不易,点个赞呗,谢谢啦~

  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTML元素语义化补充之css函数(三)

文章目录 CSS中的函数css函数–varcss函数–calccss函数–blurcss函数–gradientlinear-gradient的使用 CSS中的函数 ◼ 在前面我们有使用过很多个CSS函数: 比如rgb/rgba/translate/rotate/scale等; CSS函数通常可以帮助我们更加灵活的来编写样式的值&#xff1b; ◼ 下面有几…

自动驾驶轨迹规划之时空语义走廊(一)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.摘要 2.系统架构 3.MPDM 4.时空语义走廊 ​4.1 种子生成 4.2 具有语义边界的cube inflation ​4.3 立方体松弛 本文解析了丁文超老师…

【机器学习300问】47、如何计算AUC?

一、AUC是什么&#xff1f; &#xff08;1&#xff09;文绉绉的定义 AUCArea Under the Curve中文直译叫“曲线下面积”&#xff0c;AUC名字里面的Curve曲线指的就是ROC曲线&#xff0c;关于ROC曲线的相关知识我已经在之前的文章中详细说过了&#xff0c;有需要的友友可以点击…

阿里云服务器(Ubuntu22)上的MySQL8数据库下载,安装和远程连接

最近阿里云centos主机到期了改为使用Ubuntu操作系统&#xff0c;在上面安装mysql并远程连接出现了一系列问题并解决。 之前在centos系统上下载mysql8的教程如下&#xff1a; 阿里云服务器&#xff08;centos7&#xff09;上的MySQL8数据库下载&#xff0c;安装和远程连接 主机操…

10、chrome拓展程序的实现

一、拓展程序的实现 拓展程序项目的构成 和前端项目一样&#xff0c;拓展程序也是有Html、CSS、JS文件实现的&#xff0c;现在看来它就是一个静态的前端页面。但是不同的是&#xff0c;拓展程序中还需要额外的一个清单文件&#xff0c;就是manifest.json&#xff0c;清单文件可…

Fabric Measurement

Fabric Measurement 布料测量

stm32平衡车

目录 一.所需材料 二.PID算法&#xff08;简单说明&#xff09; 直立环 速度环 串级PID 三.使用到的外设 1.定时器输出比较-PWM 2.定时器编码器模式 3.编码器读取速度 4.电机驱动函数 5.外部中断 四、小车 调试 一.所需材料 1.陀螺仪MPU6050--读取三轴的加速度…

基于springboot+vue的旅游推荐系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

自定义序列化

3.2.2.自定义序列化 RedisTemplate可以接收任意Object作为值写入Redis&#xff1a; 只不过写入前会把Object序列化为字节形式&#xff0c;默认是采用JDK序列化&#xff0c;得到的结果是这样的&#xff1a; 缺点&#xff1a; 可读性差内存占用较大 我们可以自定义RedisTempla…

Python 从0开始 一步步基于Django创建项目(3)使用Admin site管理数据模型

本文内容建立在《Python 从0开始 一步步基于Django创建项目&#xff08;2&#xff09;创建应用程序&数据模型》的基础上。 Django提供的admin site&#xff0c;使得网站管理员&#xff0c;能够轻松管理网站的数据模型。 本文首先创建‘管理员账户’&#xff0c;即超级用户…

springboot296基于个性化定制的智慧校园管理系统设计与开发

智慧校园管理系统的设计与实现 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统校园综合信息管理难度大&…

C++夯实基础

C在线学习笔记 第一阶段&#xff1a;基础 一、环境配置 1.1.第一个程序&#xff08;基本格式&#xff09; ​ #include <iosteam> using namespace std;int main(){cout<<"hello world"<<endl;system("pause"); }​ 模板 #include…

【比较函数坑点】D. Li Hua and Tree

题目 #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e5 5, inf 1e18, maxm 4e4 5; const int mod 1e9…

Qt creator构建DLL库

文章目录 一、构建DLL库二、隐式调用DLL库 一、构建DLL库 Qt creator创建DLL项目。 实现功能函数。 运行代码&#xff0c;debug目录下会有.dll和.lib文件。 二、隐式调用DLL库 QT新建控制台项目。将.lib文件和与之关联的头文件赋值到项目文件夹。 3. 添加头文件和外部依赖库…

创建vue3项目并集成cesium插件运行

创建vue3项目并集成cesium插件 一、vue项目创建 1、前期准备 node.js&npm或yarn 本地开发环境已经安装好。 参考安装 2、安装vue-cli&#xff0c;要求3以上版本 #先查看是否已经安装 vue -V#安装 npm install -g vue/cli4.5.17 示例&#xff1a;Idea工具 页面 Termin…

HE切片+qupath识别TIL和成纤维细胞文献(三阴性乳腺癌)

An Open-Source, Automated Tumor-Infiltrating Lymphocyte Algorithm for Prognosis in Triple-Negative Breast Cancer An Open-Source, Automated Tumor-Infiltrating Lymphocyte Algorithm for Prognosis in Triple-Negative Breast Cancer - PubMed (nih.gov) 试验设计 …

Matplotlib中英文使用不同字体的最优解

中英文使用不同字体&#xff0c;我们需要解决两个需求&#xff1a; 第一个需求&#xff1a;要用中文字体显示中文&#xff0c;不能全部都是框框。第二个需求&#xff1a;横纵坐标的数字用英文字体显示&#xff0c;英文用英语字体显示。 方法很简单&#xff0c;只需要添加一行…

RabbitMQ之Plugins插件----AMQP对接MQTT

1.启用插件 rabbitmq-plugins enable rabbitmq_mqtt 2.检查是否启动成功&#xff0c;打开rabbitmq后台 3.概念&#xff1a; AMQP是由交换器和queue队列组成的消息队列机制&#xff0c;MQTT是由订阅主题组成的消息机制 1.MQTT创建连接时会向rabbitmq创建一个自己的queue&…

SpringCloud之网关组件Gateway学习

SpringCloud之网关组件Gateway学习 GateWay简介 Spring Cloud Gateway是Spring Cloud的⼀个全新项目&#xff0c;目标是取代Netflix Zuul&#xff0c;它基于Spring5.0SpringBoot2.0WebFlux&#xff08;基于高性能的Reactor模式响应式通信框架Netty&#xff0c;异步⾮阻塞模型…

基于python+vue超市管理系统flask-django-php-nodejs

课题主要分为二大模块&#xff1a;即管理员模块和员工模块&#xff0c;主要功能包括&#xff1a;个人信息修改、员工信息、商品信息、商品进货、商品出库、商品销量等&#xff1b; 目录 摘 要 I Abstrac II 目录 III 1绪论 1 1.1 研究背景 3 1.1.1国内研究现状 3 1.1.2国外研究…