C语言 -- 动态内存管理

news2025/1/13 2:41:44

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.coloradmin.cn/o/1959393.html

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

相关文章

嵌入式学习——C语言指针(一)

一、地址和指针的概念 地址:内存单元的编号。 指针:一个变量的首地址就叫做该变量的指针。 1、内存中存取数据的方式 1)直接存取 直接用变量名存取变量所占内存单元的内容 例: int y,x 3; y 3*x2; 2&#…

【日记】今天又是哪朵小云不开心了呀(1886 字)

正文 上午上班没多久,天就特别阴,感觉像是要下暴雨的样子。前台接了一个电话,家里人打来的,她妈妈叮嘱她,要注意一点。他们那边已经开始下了。她转过头对我笑笑说,原来下雨在一个城里也能不同步。 当时我笑…

AttributeError: ‘NoneType‘ object has no attribute ‘shape‘

AttributeError: ‘NoneType‘ object has no attribute ‘shape‘ 目录 AttributeError: ‘NoneType‘ object has no attribute ‘shape‘ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰…

多家隧道代理价格:阿布云、快代理、小象代理、熊猫代理和亿牛云……

随着奥运的热度攀升,各大品牌也在抓紧时机赶上这波奥运热潮,随之而来的大量数据信息收集和分析工作也接踵而至,在这一数据采集过程中,HTTP代理的质量和价格对企业的效率和成本调控重要性不言而喻。我们大部分人在日常购买产品的时…

2235234234

作者主页: 作者主页 本篇博客专栏:C 创作时间 :2024年6月20日 最后: 十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我: 1.一个冷知识: …

细说MCU的DAC1实现两个通道同时输出的方法

目录 一、参考硬件 二、 建立新工程 1.配置DAC 2.配置DMA 3.配置定时器 4.配置时钟和Debug 三、修改代码 1.初始化定时器和DAC 2.定义波形数据 3.波形数据的产生方法 四、查看结果 一、参考硬件 本项目依赖的软件和硬件工程参考本文作者写的文章: 细说MC…

手写RPC框架,与Spring整合,基于Netty作为网络框架,protobuf作为序列化协议。可以和实际项目相结合完美运行

注:由于RPC框架过于庞大所以本篇文章只是作为阅读RPC源码的一个指导,设计精巧之处还需要各位读者结合源码进行实践 RPC源码地址:https://github.com/xhpcd/rpc git clone: https://github.com/xhpcd/rpc.git 如果觉得有收获麻烦留下一颗st…

使用 Easysearch 打造企业内部知识问答系统

大家可能都有这样的经历,刚入职一家企业时,同事往往会给你分享一些文档资料,有可能是产品信息、规章制度等等。这些文档有的过于冗长,很难第一时间找到想要的内容。有的已经有了新版本,但员工使用的还是老版本。 基于…

centos7-8/redhat7-8一键安装配置vsftp服务

1.脚本介绍 1.1.介绍: linux下一键安装及配置vsftpd服务 ,通过执行install.sh脚本,脚本会根据参数区域的值执行安装和配置vsftp服务,安装后会创建一个默认ftp用户wangxf密码wangxf2023 1、支持自定义安装(更改脚本内参数值) 2、…

javaweb_01:http

一、什么是http HTTP 是一个简单的请求-响应协议,它通常运行在TCP之上,它指定了客户端可能发送给服务器什么样的消息,以及得到什么样的响应。请求和响应都是以ASCll码的形式给出;而消息内容则具有一个类似MIME的格式。这个简单模…

面试Redis篇

本篇主要总结一下面试官可能会在Redis上询问的主要问题。 Redis的使用场景 问:你的项目中哪些场景中用到了Redis? 答:根据你的项目回答,一般会在一下几个部分缓存、分布式锁...... 缓存 缓存穿透 查询一个不存在的数据&#xff…

黑马点评--给店铺类型查询添加缓存

controller/ShopTypeController.java /*** 店铺分类查询,用于展示首页头部店铺分类* return*/GetMapping("list")public Result queryTypeList() {return typeService.queryList();} service/IShopTypeService.java Result queryList(); service/impl/S…

4234324

作者主页: 作者主页 本篇博客专栏:C 创作时间 :2024年6月20日 最后: 十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我: 1.一个冷知识: …

alg-in-go-1:动态连通性问题

前言: 有本算法书叫:Algorithms 4th Edition.pdf,它是用java实现的,但是算法的内核是一样,不在乎于语言,考虑到java当今的…, 咱们尝试用golang学习算法. 问题: 思考🤔&#xff…

弹幕背后:B站UP主创作服务解析

引言 在B站,每一条飘过的弹幕都是一个故事的碎片,它们汇聚成一幅幅生动的社交画卷。这里,不仅仅是一个视频分享平台,弹幕背后更是一个充满活力的创作者生态系统。B站以其独特的弹幕文化,为创作者和观众之间搭建起了一座…

【电控笔记-xuan】各种估测器扰动估计性能比较

各种扰动观测器观测结果 蓝色: 扰动值 隆博戈估测器扰动补偿 论文53disturb扰动补偿 2order eso 观测

《系统架构设计师教程(第2版)》第13章-层次式架构设计理论与实践-01-层次式体系结构概述

文章目录 1. 常用层次是架构2. 层次式架构设计的注意点2.1 污水池反模式2.2 应用变得庞大 本章教材又赘述了一遍架构的定义和层次架构风格的概述,我之前的笔记都写了 架构的定义回看《第7章-系统架构设计基础知识-01-软件架构(Software Architecture&…

AD的问题

连续放置同规则元件:先选择再按Tab编辑放置; 拖动元件:(shift 空格 :旋转元件;原理图中按x水平,按y垂直翻转)按ctrl键可以丝滑流畅放置 测试距离:RM 距离单位转…

初学Mybatis之动态 SQL

动态 SQL 是指根据不同的条件生成不同的 SQL 语句 动态 SQL 详情请看链接 搭建环境: mysql 建立博客表 CREATE TABLE blog(id VARCHAR(50) NOT NULL COMMENT 博客id,title VARCHAR(100) NOT NULL COMMENT 博客标题,author VARCHAR(30) NOT NULL COMMENT 博客作者…

华为od机试真题:悄悄话(Python)

2024华为OD机试(C卷D卷)最新题库【超值优惠】Java/Python/C合集 题目描述 给定一个二叉树,每个节点上站一个人,节点数字表示父节点到该节点传递悄悄话需要花费的时间。 初始时,根节点所在位置的人有一个悄悄话想要传…