C语言 -- 动态内存管理

C语言 -- 动态内存管理

  • 1. 为什么要有动态内存分配
  • 2. malloc 和 free
    • 2.1 malloc
    • 2.2 free
  • 3. calloc 和 realloc
    • 3.1 calloc
    • 3.2 realloc
  • 4. 常见的动态内存的错误
    • 4.1 对NULL指针的解引用操作
    • 4.2 对动态开辟空间的越界访问
    • 4.3 对非动态开辟内存使用free释放
    • 4.4 使用free释放一块动态开辟内存的一部分
    • 4.5 对同一块动态内存多次释放
    • 4.6 动态开辟内存忘记释放(内存泄漏)
  • 5. 动态内存经典笔试题分析
    • 5.1 题目1:
    • 5.2 题目2:
  • 5.3 题⽬3:
  • 5.4 题目4:
  • 6. 柔性数组
    • 6.1 柔性数组的特点:
    • 6.2 柔性数组的使用
  • 6.3 柔性数组的优势
  • 7. 总结C/C++中程序内存区域划分

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

我们已经掌握的内存开辟放式有:
在这里插入图片描述
但是上述的开辟空间的方式有两个特点:

  • 空间开辟大小是固定的。
  • 数组在申明的时候,必须指定数组的长度,数组空间⼀旦确定了大小不能调整。

但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。
C语言引入了动态内存开辟,让程序员自己可以申请和释放空间,就比较灵活了。

2. malloc 和 free

2.1 malloc

C语言提供了⼀个动态内存开辟的函数:
在这里插入图片描述
当我们用void * 指针接收的时候,这就完蛋了,void * 的指针不能++,或者- -,不能对她解引用操作。
虽然malloc函数不知道存放什么类型的数据,但是我们自己在申请内存空间的时候大概想好要存放什么类型的数据。对于整形数据的访问使用,是不是用整形指针最合适了,因为整形指针解引用访问4个字节,+1跳过4个字节,这是在合适不过的了。因此我们一般使用的时候一般会把它强制转换成 int *,然后直接赋值给一个int *的指针变量。
如下:
在这里插入图片描述
这个函数向内存申请⼀块连续可用的空间,并把这块空间的起始位置的地址返回来。

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

在这里插入图片描述
如果malloc申请的空间不放值,直接打印会产生随机值。malloc 只负责帮你申请块空间,但是他里面的值是随机的(未知的)。
在这里插入图片描述

注意: malloc 申请的空间在内存的堆区。

2.2 free

C语言提供了另外⼀个函数free,专门是用来做动态内存的释放和回收的,函数原型如下:
在这里插入图片描述
free函数用来释放动态开辟的内存。

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

malloc和free都声明在 stdlib.h头文件中。
测试代码如下:
在这里插入图片描述

free函数是没有能力把p置为空的,站在free函数这个角度,free你要给它传个指针,free函数参数是一个指针变量,你要给它传,传的也是指针变量,把p传给ptr,
这叫值传递,ptr就是p的一份临时拷贝,在free函数内部,对ptr的修改是不会影响外面的p,所以它并没有能力把p置为空,只能手动置为空。想象一下,free函数内部如果想要把这个参数,外边传给他们的这个参数p置为空的话,你应该传p的地址过去才可以。

3. calloc 和 realloc

3.1 calloc

C语言还提供了⼀个函数叫 calloc , calloc 函数也用来动态内存分配。原型如下:
在这里插入图片描述

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

测试代码如下:
在这里插入图片描述
所以如果我们对申请的内存空间的内容要求初始化,那么可以很方便的使用calloc函数来完成任务。

3.2 realloc

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

函数原型如下:
在这里插入图片描述

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

在这里插入图片描述
由于上述的两种情况,realloc函数的使用就要注意一些。
测试代码如下:
在这里插入图片描述

调试代码:
在这里插入图片描述
realloc 该函数除了能够调整空间之外,他还能实现和malloc一样的功能。
在这里插入图片描述

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

4.1 对NULL指针的解引用操作

在这里插入图片描述
下面是正确写法:
在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述
上面这种写法会导致程序崩溃。

在这里插入图片描述

在这里插入图片描述
上面这个程序结束以后,申请的空间才被操作系统回收。

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

在这里插入图片描述
上面这种写法会导致程序崩溃。

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

在这里插入图片描述
下面是解决方案:
在这里插入图片描述

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

在这里插入图片描述

解决方案:
在这里插入图片描述

忘记释放不再使用的动态开辟的空间会造成内存泄漏。
切记:动态开辟的空间⼀定要释放,并且正确释放。

5. 动态内存经典笔试题分析

5.1 题目1:

在这里插入图片描述
请问运行Test函数会有什么样的结果?
程序会崩溃。
代码解析:
在这里插入图片描述
上面代码存在三个问题如下:

在这里插入图片描述
下面是改正上面代码:
方法一:
在这里插入图片描述

方法二:
在这里插入图片描述

5.2 题目2:

典型的返回栈空间地址的问题
在这里插入图片描述
请问运行Test函数会有什么样的结果?
在这里插入图片描述
代码解析:
在这里插入图片描述
解决方案:
在这里插入图片描述
下面也是一个返回栈空间地址的问题
在这里插入图片描述

5.3 题⽬3:

在这里插入图片描述
请问运行Test函数会有什么样的结果?
在这里插入图片描述
上面代码看似没有问题,但是存在内存泄露问题。
改正如下:在这里插入图片描述

5.4 题目4:

在这里插入图片描述
代码分析:
在这里插入图片描述
上述代码应该在free(str)之后,应该手动把str置为空。

6. 柔性数组

也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。C99中,结构中的最后⼀个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
在这里插入图片描述
例如:
在这里插入图片描述
有些编译器会报错无法编译可以改成:
在这里插入图片描述

6.1 柔性数组的特点:

• 结构中的柔性数组成员前面必须至少⼀个其他成员。
• sizeof返回的这种结构大小不包括柔性数组的内存。
• 包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
例如:
在这里插入图片描述

6.2 柔性数组的使用

在这里插入图片描述

6.3 柔性数组的优势

上述的St结构也可以设计为下面的结构,也能完成同样的效果。
在这里插入图片描述
上述 代码1 和 代码2 可以完成同样的功能,但是 方法1 的实现有两个好处:
在这里插入图片描述
扩展阅读:
C语言结构体里的数组和指针

7. 总结C/C++中程序内存区域划分

在这里插入图片描述
C/C++程序内存分配的几个区域:

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
  2. 堆区(heap):⼀般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。
  3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
  4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。

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

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

相关文章

【力扣】SQL题库练习5

高级查询和连接 1341.电影评分 表:Movies ------------------------ | Column Name | Type | ------------------------ | movie_id | int | | title | varchar | ------------------------ movie_id 是这个表的主键(具有唯一值的列)。 ti…

力扣131题:分割回文串的 Java 实现

引言 力扣(LeetCode)是一个在线编程平台,提供了大量的编程题目供开发者练习。第131题“分割回文串”是一个有趣的字符串处理问题,要求将一个字符串分割成尽可能多的回文子串。本文将介绍如何使用 Java 解决这个问题。 题目描述 …

05 capture软件创建元器件库(以STM32为例)

05 创建元器件库_以STM32为例 一、新建原理图库文件二、新建器件三、开始创建元器件 一些IC类元件,需要自己创建元器件库。 先看视频,然后自己创建STM32F103C8T6的LQFP48的元器件。 STM32F103C8T6是目前为止,自己用的最多的芯片。 先要有数据…

mysqlMHA

mysqlMHA 什么是MHA ​ 高可用模式下的故障切换,基于主从复制. ​ 至少需要3台 ​ 故障切换过程在0-30秒之内. ​ 这过程和keepalive比较像,也是通过vip地址,根据vip地址所在的主机,确定主备. ​ 主和备不是靠优先级确定的,主从复制的时候就确定了主,备是在MHA的过程中确…

Qt自定义MessageToast

效果&#xff1a; 文字长度自适应&#xff0c;自动居中到parent&#xff0c;会透明渐变消失。 CustomToast::MessageToast(QS("最多添加50张图片"),this);1. CustomToast.h #pragma once#include <QFrame>class CustomToast : public QFrame {Q_OBJECT pub…

【学习笔记】解决Serial Communication Library编译问题

【学习笔记】解决编译 Serial Communication Library 时的 Catkin 依赖问题 Serial Communication Library 是一个用 C 编写的用于连接类似 rs-232 串口的跨平台库。它提供了一个现代的 C 接口&#xff0c;它的工作流程设计在外观和感觉上与 PySerial 相似&#xff0c;但串口速…

ControlNet on Stable Diffusion

ControlNet on Stable Diffusion 笔记来源&#xff1a; 1.Adding Conditional Control to Text-to-Image Diffusion Models 2.How to Use OpenPose & ControlNet in Stable Diffusion 3.ControlNet与DreamBooth&#xff1a;生成模型的精细控制与主体保持 4.Introduction t…

光猫设置桥接 路由器pppoe拨号 设置正常访问光猫 (openwrt)

网络信息展示 光猫桥接很简单吧&#xff0c;就不说了。先来列出修改前的网络接口和网络信息。 光猫192.168.1.1&#xff0c;openwrt 10.0.0.0/8 初始配置 需要记录的信息&#xff1a;WAN的网络设备&#xff08;eth1&#xff09;&#xff0c;光猫的IP&#xff08;192.168.1.1&am…

StarryCoding-35:鼠鼠我鸭

题目描述 在一个叫做酱西功爷枝叶鸡树学院的地方有&#x1d45b;n只小动物&#xff0c;要么是鼠鼠&#xff0c;要么是鸭鸭&#xff0c;从11到&#x1d45b;n编号&#xff0c;每只小动物有个体重&#x1d44e;&#x1d456;ai​。 在这个学校里&#xff0c;存在一种神奇的魔法…

Symfony 入门指南:快速安装与基础配置

Symfony 入门指南&#xff1a;快速安装与基础配置 Symfony 是一个强大而灵活的 PHP 框架&#xff0c;广泛应用于构建现代 Web 应用程序。本指南将带您一步一步地了解如何快速安装 Symfony&#xff0c;并完成基本配置&#xff0c;以便您能够开始使用这个强大的框架。 目录 引…

使用法国云手机进行面向法国的社媒营销

在当今数字化和全球化的时代&#xff0c;社交媒体已经成为企业营销和拓展市场的重要工具。对于想进入法国市场的企业来说&#xff0c;如何在海外社媒营销中脱颖而出、抓住更多的市场份额&#xff0c;成为了一个关键问题。法国云手机正为企业提供全新的营销工具&#xff0c;助力…

Spring Boot多租户配置与实现

在现代应用程序中&#xff0c;多租户架构是一种非常流行的设计模式。多租户架构允许多个客户&#xff08;租户&#xff09;共享同一个应用程序实例&#xff0c;同时确保数据的隔离性和安全性。本文将详细介绍如何在Spring Boot应用程序中配置和实现多租户支持&#xff0c;并提供…

《人工智能大语言模型技术发展研究报告(2024)》【下载】

《人工智能大语言模型技术发展研究报告&#xff08;2024&#xff09;》下载 自2023年起&#xff0c;大模型技术产品的快速迭代和升级&#xff0c;已经成为全球科技竞争的关键因素。由中国软件评测中心发布的《人工智能大语言模型技术发展研究报告&#xff08;2024&#xff09;》…

kafka详解及应用场景介绍

Kafka架构 Kafka架构&#xff0c;由多个组件组成&#xff0c;如下图所示&#xff1a; 主要会包含&#xff1a;Topic、生产者、消费者、消费组等组件。 服务代理&#xff08;Broker&#xff09; Broker是Kafka集群中的一个节点&#xff0c;每个节点都是一个独立的Kafka服务器…

反激Flyback从逆向到初步设计(UC2844)

一.Flyback基本拓扑 国标gb/t 12325-2008《电能质量供电电压偏差》规定&#xff1a;220v单向供电电压偏差为标称电压的-10%&#xff0c;7%。 对应220V的标称电压&#xff0c;其浮动范围是在198~235.4V。以下运算均基于此规定进行。 首先220V进入EMI模块&#xff0c;消除差模干扰…

【Docker】Windows11环境下的安装

前置依赖环境配置 确保虚拟化开启 搜索栏直接搜索如下功能 勾选下面两个选项&#xff0c;确定 重启电脑&#xff0c;以管理员身份打开PowerShell wsl --status wsl --update打开微软应用商店选择一个Ubuntu版本下载并打开 输入一个用户名和密码 然后就可以在Windows下使…

FlowUs与生成式AI结合的未来展望:智能助手问问AI chat与自主代理Agent的应用

生成式AI在对话系统&#xff08;Chat&#xff09;和自主代理&#xff08;Agent&#xff09;中的应用将会带来显著的技术进步和商业机会。 对话系统&#xff08;Chat&#xff09; 对话系统是一种人工智能软件&#xff0c;它能够模拟人类对话&#xff0c;通过自然语言处理&…

go-kratos 学习笔记(7) 服务发现服务间通信grpc调用

服务发现 Registry 接口分为两个&#xff0c;Registrar 为实例注册和反注册&#xff0c;Discovery 为服务实例列表获取 创建一个 Discoverer 服务间的通信使用的grpc&#xff0c;放到data层&#xff0c;实现的是从uses服务调用orders服务 app/users/internal/data.go 加入 New…

2024安全大模型技术与市场研究报告

大模型驱动的AIGC引发技术革命&#xff0c;国资委强调国企需加大AI投入。大模型解决网络安全行业攻防不对等问题&#xff0c;国内外企业纷纷推出基于大模型的网络安全产品&#xff0c;AI将改变网络安全产品格局。 自 2022 年底开始&#xff0c;以 LLM(大语言模型&#xff0c;简…

PHP基础语法-Part2

if-else语句、switch语句 与其他语言相同 循环结构 for循环while循环do-while循环foreach循环&#xff0c;搭配数组使用 foreach ($age as $avlue) //只输出值 {xxx; } foreach ($age as $key > $avlue) //键和值都输出 {xxx; }foreach ($age as $key >…