当前位置: 首页 > news >正文

C语言--动态内存管理1

目录

  • 前言
  • 动态内存函数介绍
    • malloc
    • free
    • calloc
    • realloc
  • 常见的动态内存错误
    • 对NULL指针的解引用操作
    • 对动态开辟空间的越界访问
    • 对非动态开辟内存使用free释放
    • 使用free释放一块动态开辟内存的一部分
    • 对同一块动态内存多次释放
    • 动态开辟内存忘记释放(内存泄漏)
  • 对通讯录进行优化

前言

我们目前已知的内存开辟方式是要指定长度的,比如以下这两种方式

int val = 20;
char arr[10] = {0};

我们发现:

  1. 这些空间开辟的大小时固定的,无法被修改
  2. 如果是数组,在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配.

再比如我们的通讯录,如果我们一开始就确定了人员个数的最大值,那么一旦到达这个上限,就无法继续录入数据了,我们能不能实现一种能根据我们的需求灵活更改空间大小的方式呢?这时候我们就需要动态内存开辟空间了。

动态内存函数介绍

malloc

我们先来看书写的格式:

     void* malloc (size_t size);

malloc本质上是一个函数,它的作用是开辟内存块,它有参数,有返回值,我们现在来看看分别是什么:

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

2. 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定
因为malloc这个函数的返回值是void类型的指针,所以我们在接收的时候,要强制力类型转换为我们想要的类型,并用相应的指针来接收。比如我们要申请5个整型*的内存空间,代码就应这样书写:

     int* p=(int)malloc(20);//注意这里的20是指20个字节,即5个整型大小

值得注意的是,此时我们申请的动态内存空间是在堆区的,这有别于我们之前在栈区开辟空间。

3. 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
我们知道,对空指针解引用操作是很危险的,所以我们一定要在使用前检查一下,代码如下

//申请int* p = (int*)malloc(20);if (p == NULL){printf("%s\n", strerror(errno));return 1;}

4. 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器

free

C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收的.
书写格式如下:

void free (void* ptr);
  1. 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  2. 如果参数 ptr 是NULL指针,则函数什么事都不做
    我们将 p free掉后看一下p的地址是否发生改变。
    图1
    我们发现,虽然空间被回收了,但是p内存放的地址并没有改变,这时候如果再对其解引用便是非法访问了,所以我们要手动将p的值赋为NULL,具体代码实现如下
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>int main()
{int* p = (int*)malloc(20);if (p == NULL){printf("%s\n", strerror(errno));return 1;}free(p);p = NULL;return 0;
}

备注:mallocfree都声明在 stdlib.h 头文件中。

calloc

C语言还提供了一个函数叫 calloc , calloc 函数也用来动态内存分配。原型如下:

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

假设我们要申请十个int类型大小的空间,书写方式如下

int *p = (int*)calloc(10, sizeof(int));

realloc

我们看这个函数的前缀re,联系英语常识可以大概猜到这个函数的用途是重新,再次开辟一块空间。
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时
候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小
的调整

书写格式如下

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

1. ptr要调整的内存地址
2. size调整之后新大小
3. 返回值调整之后的内存起始位置

要注意区分的是:realloc在调整内存空间的是存在两种不同情况,分别是原有空间之后有足够大的空间原有空间之后没有足够大的空间

情况1: 原有空间之后有足够大的空间
图2
此时,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

情况2: 原有空间之后没有足够大的空间
图3
此时,realloc会找更大的空间(找不到就开辟失败了),将原来的数据拷贝到新的空间去,释放旧的空间,返回新空间的地址。

常见的动态内存错误

对NULL指针的解引用操作

我们来看下面这段代码

void test()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;
free(p);
}

我们在前面讲到过,如果malloc函数开辟空间失败,就会返回空指针,对空指针解引用很明显存在问题。

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

void test()
{
int i = 0;
int *p = (int *)malloc(10*sizeof(int));
if(NULL == p)
{
exit(EXIT_FAILURE);
}
for(i=0; i<=10; i++)
{
*(p+i) = i;
}
free(p);
}

上面这段代码当i=10的时候,已经超出我们开辟的空间范围了,这时候再解引用就会越界访问

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

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

我们前面说过: 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。所以这里我们对非动态开辟内存使用free释放肯定是行不通的

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

void test()
{
int *p = (int *)malloc(100);
p++;
free(p);
}

看这段代码我们发现,p++使得p不再指向动态内存开辟的起始位置,这样写是有问题的。

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

void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);
}

这样写是有问题的,但是如果我们释放完一次就将p赋值为空指针,这时候再对p free就不会有任何问题了。

void test()
{
int *p = (int *)malloc(100);
free(p);
p=NULL;
free(p);
}

我们在前面也讲过,如果参数 ptr 是NULL指针,则函数什么事都不做

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

void test()
{
int *p = (int *)malloc(100);
if(NULL != p)
{
*p = 20;
}
}
int main()
{
test();
while(1);
}

我们首先要了解一点的是:以上的所有函数所申请的空间,如果不想使用,需要free释放,如果不想使用free释放,在程序结束之后,也会由操作系统回收
但是,如果不使用free释放,程序也不结束,就会造成内存泄露

这里尤其要注意的点是,如果动态内存函数开辟空间是在另一个函数内部进行的,出了这个函数,这块空间是没有像局部变量一样被回收的,只有free能将它回收!!!

对通讯录进行优化

在学习了动态内存函数后,我们可以将其灵活运用到通讯录中,实现可以对达到人数上限的通讯录进行扩容。
主要修改点在于
1,初始化
我们假定初始大小为3,每次扩容大小为2。这里我们可以用,方便修改。
同时,因为我们需要对当前容量与最大容量比较决定是否扩容,所以还需一个参数capacity来存放最大容量的的数值。

#define DEFAULT_SZ 3
#define INC_SZ 2void InitContact(Contact* pc)
{pc->sz = 0;pc->data = malloc(DEFAULT_SZ * sizeof(PeoInfo));if (pc->data == NULL){printf("通讯录初始化失败:%s", strerror(errno));return;}pc->sz = 0;pc->capacity = DEFAULT_SZ;
}

2,扩容

void CheckCapacity(Contact* pc)
{if (pc->sz == pc->capacity)//判断是否达到容量上限{PeoInfo* ptr = realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){printf("扩容失败:%s\n",strerror(errno));return;}else{pc->data = ptr;pc->capacity += INC_SZ;printf("扩容成功,当前容量:%d\n", pc->capacity);}}
}

3,销毁

void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}

以上就是本章全部内容,如有出入,欢迎指正。

相关文章:

C语言--动态内存管理1

目录前言动态内存函数介绍mallocfreecallocrealloc常见的动态内存错误对NULL指针的解引用操作对动态开辟空间的越界访问对非动态开辟内存使用free释放使用free释放一块动态开辟内存的一部分对同一块动态内存多次释放动态开辟内存忘记释放&#xff08;内存泄漏&#xff09;对通讯…...

HTTPS 的工作原理

1、客户端发起 HTTPS 请求 这个没什么好说的&#xff0c;就是用户在浏览器里输入一个 https 网址&#xff0c;然后连接到 server 的 443 端口。 2、服务端的配置 采用 HTTPS 协议的服务器必须要有一套数字证书&#xff0c;可以自己制作&#xff0c;也可以向组织申请&#xf…...

游戏开发中建议使用半兰伯特光照

游戏开发中建议使用半兰伯特光照模型 在基本光照模型中求出漫反射部分的计算公式: 漫反射 = 入射光线的颜色和强度(c light) * 材质漫反射系数 (m diffuse)* 表面法线(n) * 其光源防线 (I) 在shader中为了不让 n和i的点乘结果为负数,即使用了saturate函数让值截取在[0,1]区…...

JavaScript到底如何存储数据?

1.var的迷幻操作 普遍的观点&#xff1a;JavaScript中的基本数据类型是保存在栈空间&#xff0c;而引用数据类型则是保存在堆空间里, 是否正确&#xff1f; 浏览器环境下JavaScript变量类型的运行实践结果: var a 10;console.log(a);console.log(window.a); console.log(wind…...

python实战应用讲解-【numpy专题篇】numpy应用案例(一)(附python示例代码)

目录 用Python分析二手车的销售价格 用Python构建GUI应用的铅笔草图 需要的包 实现步骤 完整代码 用Python分析二手车的销售价格 如今&#xff0c;随着技术的进步&#xff0c;像机器学习等技术正在许多组织中得到大规模的应用。这些模型通常与一组预定义的数据点一起工作…...

网络割接项目

某企业准备采购2台华为设备取代思科旧款设备,针对下列问题作出解答。 (1)做设备替换的时候,如何尽可能保证业务稳定性,请给出解决方案。 a)对现网拓扑进行分析,分析现网拓扑的规划(链路类型、cost、互联IP、互联接口等信息)、分析现网流量模型(路由协议、数据流向特…...

SpringBoot整合数据可视化大屏使用

1 前言 DataV数据可视化是使用可视化应用的方式来分析并展示庞杂数据的产品。DataV旨让更多的人看到数据可视化的魅力,帮助非专业的工程师通过图形化的界面轻松搭建专业水准的可视化应用,满足您会议展览、业务监控、风险预警、地理信息分析等多种业务的展示需求, 访问地址:h…...

蓝桥杯Web前端练习题-----水果拼盘

一、水果拼盘 介绍 目前 CSS3 中新增的 Flex 弹性布局已经成为前端页面布局的首选方案&#xff0c;本题可以使用 Flex 属性快速完成布局。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; ├── css │ └── style.…...

[攻城狮计划]如何优雅的在RA2E1上运行RT_Thread

文章目录[攻城狮计划]|如何优雅的在RA2E1上运行RT_Thread准备阶段&#x1f697;开发板&#x1f697;开发环境&#x1f697;下载BSP&#x1f697;编译烧录连接串口总结[攻城狮计划]|如何优雅的在RA2E1上运行RT_Thread &#x1f680;&#x1f680;开启攻城狮的成长之旅&#xff0…...

1.linux操作命令

1. pwd -> 打印当前绝对工作路径。 2. ls -> 查看目录的文件名 ls -> 默认列出当前目录的全部文件名 ls . -> 列出当前目录的全部文件名(.代表当前目录) ls / -> 列出根目录下的全部文件命名 ls -a -> 列出当前目录下全部文件名(包括隐藏…...

STL--vector

vector 头文件 #include<vector>向量的定义&#xff1a; vector<int> vec&#xff1b;//定义一个vec型的向量a vector<int> vec(5); //定义一个初始大小为5的向量 vector<int> vec(5,1); //初始大小为5&#xff0c;值都为1的向量二维数组&#xff1…...

Java每日一练(20230324)

目录 1. 链表插入排序 &#x1f31f;&#x1f31f; 2. 最接近的三数之和 &#x1f31f;&#x1f31f; 3. 寻找旋转排序数组中的最小值 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一…...

你掌握了吗?在PCB设计中,又快又准地放置元件

在印刷电路板设计中&#xff0c;设置电路板轮廓后&#xff0c;将零件(占地面积)调用到工作区。然后将零件重新放置到正确的位置&#xff0c;并在完成后进行接线。 组件放置是这项工作的第一步&#xff0c;对于之后的平滑布线工作是非常重要的工作。如果在接线工作期间模块不足…...

springboot学生综合测评系统

031-springboot学生综合测评系统演示录像2022开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&…...

【Unity3D】法线贴图和凹凸映射

1 法线贴图原理 表面着色器中介绍了使用表面着色器进行法线贴图&#xff0c;实现简单快捷。本文将介绍使用顶点和片元着色器实现法线贴图和凹凸映射&#xff0c;实现更灵活。 本文完整代码资源见→法线贴图和凹凸映射。 1&#xff09;光照原理 Phong 光照模型和 Blinn Phong 光…...

代码误写到master分支(或其他分支),此时代码还未提交,如何转移到新建分支?

问题背景 有时候&#xff0c;我们拿到需求&#xff0c;没仔细看当前分支是什么&#xff0c;就开始撸代码了。完成了需求或者写到一半发现开发错分支了。 比如此时新需求代码都在master分支上&#xff0c;提交必然是不可能的&#xff0c;所有修改还是要在新建分支上进行&#x…...

java多线程之线程安全(重点,难点)

线程安全1. 线程不安全的原因:1.1 抢占式执行1.2 多个线程修改同一个变量1.3 修改操作不是原子的锁(synchronized)1.一个锁对应一个锁对象.2.多个锁对应一个锁对象.2.多个锁对应多个锁对象.4. 找出代码错误5. 锁的另一种用法1.4 内存可见性解决内存可见性引发的线程安全问题(vo…...

如何免费使用chatGPT4?无需注册!

Poe体验真滴爽首先提大家问一个大家最关心的问题如何在一年内赚到一百万&#xff1f;用个插件给他翻译一下体验地址效果是非常炸裂的&#xff0c;那么我就将网址分分享给大家https://poe.com/前提&#xff1a;要有魔法&#xff0c;能够科学shangwangChatGPT-3 随便问GPT-4 模型…...

Android Flutter在点击事件上添加动画效果

在Android App的开发项目中&#xff0c;我们需要在点击事件上实现一个动画效果来提高用户的体验度。比如闲鱼底部中间按钮的那种。该怎么实现呢&#xff1f; 一起来看看吧 实现效果如图&#xff1a; ​实现思路 根据UI的设计图&#xff0c;对每个模块设计好动画效果&#xff0…...

VSCode嵌入式开发环境搭建

Vscode开发环境搭建 看这个链接就可以了&#xff0c;后面下载调试有点问题看下3.3。 在VSCode上部署STM32F1的开发环境 1. MXCube配置工程生成Makefile文件 借助正确的编译工具链进行编译&#xff0c; 2. 编译工具链搭建 编译工具链使用GCC的ARM版本 arm-none-eabi-gcc &am…...

数据结构之栈的使用

栈是计算机科学中一个重要的数据结构。它是一种特殊的线性表&#xff0c;只允许在一端进行进出操作。这一端被称为栈顶&#xff0c;另外一端被称为栈底。栈的特点是后进先出&#xff0c;即最后进入栈的元素会先被弹出栈。栈的应用广泛&#xff0c;例如在编译器中&#xff0c;栈…...

QMessageBox手动添加按钮并绑定按钮的信号

视频展示效果&#xff08;结合代码看效果更佳哦&#xff0c;代码在最下面&#xff09;&#xff1a; QMessageBox手动添加有重试效果的按钮效果图&#xff1a; 点击详细文本之后展开如下图&#xff1a; 图标可选&#xff1a; QMessageBox::Critical错误图标QMessageBox::NoIco…...

【C++进阶】位图和布隆过滤器

文章目录位图位图概念位图使用场景位图的结构构造setresettest完整代码布隆过滤器布隆过滤器概念布隆过滤器结构构造setresettest完整版代码位图 位图概念 所谓位图&#xff0c;就是用每一位来存放某种状态&#xff0c;适用于海量数据&#xff0c;数据无重复的场景。通常是用…...

Android开发-Android UI与布局

01 Android UI 1.1 UI 用户界面(User Interface&#xff0c;简称 UI&#xff0c;亦称使用者界面)是系统和用户之间进行交互和信息交换的媒介&#xff0c;它实现信息的内部形式与人类可以接受形式之间的转换。软件设计可分为两个部分&#xff1a;编码设计与UI设计。 1.2 Andr…...

在不丢失数据的情况下解锁锁定的 Android 手机的 4 种方法

尽管您可以使用指纹解锁手机&#xff0c;但大多数智能手机都需要 PIN 码、图案或字母数字代码作为主密码。如果您有一段时间没有输入手机密码&#xff0c;很容易忘记。正是由于这个原因&#xff0c;即使您打开了指纹解锁&#xff0c;大多数智能手机也会让您每天至少输入一次 PI…...

【11】核心易中期刊推荐——人工智能 | 图形图像处理

🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…...

Spring 中的事件发布与监听

主要代码在org.springframework.context&#xff0c;org.springframework.context.event包中 事件发布与监听主要包含以下角色&#xff1a; 事件&#xff1a;ApplicationEvent事件监听器&#xff1a;ApplicationListener SmartApplicationListener GenericApplicationListene…...

c++ 一些常识 2

前言 今天主要讲类相关概念。 构造和析构函数是否可以抛出异常 在构造函数中抛出异常&#xff0c;控制权会转出构造函数之外&#xff0c;对象的析构函数不会被调用&#xff0c;造成内存泄漏。 如果析构函数中抛出异常&#xff0c;而且没有在当地捕捉&#xff0c;析构函数便执…...

用嘴写代码?继ChatGPT和NewBing之后,微软又开始整活了,Github Copilot X!

用嘴写代码&#xff1f;继ChatGPT和NewBing之后&#xff0c;微软又开始整活了&#xff0c;Github Copilot X&#xff01; AI盛行的时代来临了&#xff0c;在这段时间&#xff0c;除了爆火的GPT3.5后&#xff0c;OpenAI发布了GPT4版本&#xff0c;同时微软也在Bing上开始加入了A…...

3分钟阐述这些年我的 接口自动化测试 职业生涯经验分享

接口自动化测试学习教程地址&#xff1a;https://www.bilibili.com/video/BV1914y1F7Bv/ 你好&#xff0c;我是凡哥。 很高兴能够分享我的接口自动化测试经验和心得体会。在我目前的职业生涯中&#xff0c;接口自动化测试是我经常进行的一项任务。通过不断地学习和实践&#xf…...

判断网站是什么系统做的/广州广告公司

之前想做去雾算法在果园对靶的应用&#xff0c;想要搜集一些资料&#xff0c;包括何凯明博士在IEEE收录的一篇去雾论文Single Image Haze Removal Using Dark Channel Prior-IEEE-Xplore官网论文链接 如果没有特殊渠道获取&#xff0c;得是IEEE允许的一些机构&#xff0c;并且需…...

北京信息网招聘最新/旺道seo推广有用吗

点击上方“程序IT圈”&#xff0c;选择“置顶公众号”技术文章第一时间送达&#xff01;作者&#xff1a;废物大师兄 cnblogs.com/cjsblog/p/9756978.html1. 前言1.1. 集成方式Spring Boot中集成Elasticsearch有4种方式&#xff1a;REST ClientJestSpring DataSpring Data Elas…...

如何在网站做引流/百度后台管理

Vehicle veh1 new Vehicle(); 通常把这条语句的动作称之为创建一个对象&#xff0c;其实&#xff0c;它包含了四个动作。 1&#xff09;右边的“new Vehicle”&#xff0c;是以Vehicle类为模板&#xff0c;在堆空间里创建一个Vehicle类对象&#xff08;也简称为Vehicle对象&am…...

临沂网站建设和轶件安装/电脑优化软件哪个好用

Selenium是一个web自动化测试框架。用它可以实现web应用自动化测试。不过&#xff0c;我不只是用它来做测试&#xff0c;我还用它从电子商务网站签到页面爬取javascript生成的或AJAX的内容。 作为程序员&#xff0c;我不满足于使用Selenium IDE来记录和重放宏记录。那样很蹩脚&…...

天堂网长尾关键词挖掘网站/全球最大的中文搜索引擎

1、安装 Yum install -y freeradius freeradius-mysql freeradius-utils 2、配置 1&#xff09;修改 clients.conf # vi /usr/local/etc/raddb/clients.conf 在最后增加如下几行&#xff1a; client 172.18.5.88 { 增加认证体&#xff0c;填写OMA的ip地址 s…...

视频做网站背景/厦门百度关键词推广

JOL全称为Java Object Layout&#xff0c;是用来分析JVM中对象布局的工具&#xff0c;它可以帮我们在运行时计算某个对象的大小。 引入JOL依赖&#xff0c;如下&#xff1a; <!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core --> <dependency>…...