C系列-动态内存管理

 🌈个人主页: 会编程的果子君
💫个人格言:“成为自己未来的主人~” 

 

目录

 为什么要有动态内存分配

malloc和free

malloc

free

calloc和realloc

calloc

realloc

常见的动态内存的错误

对NULL指针的解引用操作

 ​编辑  

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

 ​编辑  

对非动态开辟内存使用free函数

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

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


 为什么要有动态内存分配

我们已经掌握的内存开辟方式有:

int val = 20;//在栈空间上开辟4个字节
char arr[10] = { 0 };//在栈空间上开辟10个字节的连续空间

但是上述的开辟空间的方式有两个特点:

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

但是对于空间的需求,不仅仅是上述的情况,有时候我们需要的空间大小在程序运行的时候我们才能知道,那数组的编译时开辟空间的方式就不能满足了。

C语言引入了动态内存开辟,让程序员自己可以申请和释放空间,就比较灵活

malloc和free

malloc

c语言提供了一个动态内存开辟的函数

void* malloc(size_t size);

这个函数想内存申请一块连续可以的空间,并返回指向这块空间的指针

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

free

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

void free(void* str);

free函数用来释放动态开辟的内存。

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

malloc和free都声明在stdlib.h头文件当中

举个例子:

#include<stdio.h>
#include<stdlib.h>int main()
{int arr[10] = { 0 };int* ptr = NULL;ptr=(int*)malloc(10 * sizeof(int));if (ptr != NULL){int i = 0;for (i = 0; i < 10; i++){*(ptr + i) = i;}}free(ptr);//释放ptr所指向的动态内存ptr = NULL;return 0;
}

calloc和realloc

calloc

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

void* calloc(size_t num, size_t size);

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

举个例子:

#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)calloc(10, sizeof(int));if (NULL != p){int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}}free(p);p = NULL;return 0;
}

 

 所以如果我们对申请的内存空间的内容要求初始化,那么可以很方便的使用calloc函数来完成任务

realloc

  • realloc函数的出现让动态内存管理更加灵活
  • 有时我们发现过去申请的空间太小了,有时候我们又觉得申请的空间过大了,所以为了合理的分配内存,我们一定要学会对内存的大小做灵活的调整,那realloc函数就可以完成这个工作

函数原型如下:

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

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

1.要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不会发生变化

2.原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。

由于上述的两种情况,realloc函数的使用就要注意一些

#include<stdio.h>
#include<stdlib.h>int main()
{int* ptr = (int*)malloc(100);if (ptr != NULL){//业务处理}else{return 1;}//拓展容量//代码1-直接将realloc的返回值放到ptr中ptr = (int*)realloc(ptr, 1000);//申请失败的话会怎么样?//代码2-先将realloc函数的返回值放到p中,不为NULL,在放到ptr中int* p = NULL;p = realloc(ptr, 1000);if (p != NULL){ptr = p;}//业务处理free(ptr);ptr = NULL;return 0;
}

常见的动态内存的错误

对NULL指针的解引用操作

#include<stdio.h>
#include<stdlib.h>
void test()
{int* p = (int*)malloc(INT_MAX / 4);*p = 20;//如果p的值是NULL,就会有问题free(p);
}int main()
{test();return 0;
}

   

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

#include<stdio.h>
#include<stdlib.h>
void test()
{int i = 0;int* p = (int*)malloc(10 * sizeof(int));if (NULL == p){perror("malloc");}for (i = 0; i <= 10; i++){*(p + i) = i;//当i是10的时候越界访问}free(p);
}
int main()
{test();return 0;
}

   

对非动态开辟内存使用free函数

 

#include<stdio.h>
#include<stdlib.h>
void test()
{int a = 10;int* p = &a;free(p);//ok?
}
int main()
{test();return 0;
}

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

 

#include<stdio.h>
#include<stdlib.h>
void test()
{int* p = (int*)malloc(100);p++;free(p);//p不再指向动态内存的起始位置
}
int main()
{test();return 0;
}

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

#include<stdio.h>
#include<stdlib.h>
void test()
{int* p = (int*)malloc(100);if (NULL != p){*p = 20;}
}
int main()
{test();while (1);
}

忘记释放不再使用的动态开辟的空间会造成内存泄漏

切记:动态开辟的空间一定要释放,并且正确释放

 

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

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

相关文章

ES6-const

一、基本用法 - 语法&#xff1a;const 标识符初始值;注意:const一旦声明变量&#xff0c;就必须立即初始化&#xff0c;不能留到以后赋值 - 规则&#xff1a;1.const 声明一个只读的常量&#xff0c;一旦声明&#xff0c;常量的值就不能改变2.const 其实保证的不是变量的值不…

查看自己电脑是arm还是x64(x86);linux操作系统识别

1、查看自己电脑是arm还是x64&#xff08;x86&#xff09; linux 参考&#xff1a; https://liuweiqing.blog.csdn.net/article/details/131783851 uname -a如果输出是 x86_64&#xff0c;那么你的系统是 64 位的 x86 架构&#xff08;通常我们称之为 x64&#xff09;。如果…

2023高精地图甲级测绘资质最新名单【高德地图】

根据2023年自然资源部公布的名单显示&#xff0c;以下公司通过“地图甲级测绘资质”换证审核&#xff0c;也就意味着&#xff0c;以下这些公司可以继续从事电子地图的采集和制作、商业合作等相关业务。 而这一点&#xff0c;对于以电子地图导航为主要业务支撑的企业至关重要。…

C-C++内存管理

C/C内存分布 内存的分配方式有几种&#xff1f; 静态内存分配&#xff08;Static Memory Allocation&#xff09;&#xff1a; 静态内存分配是在编译时确定内存大小和位置的分配方式。全局变量、静态变量和常量都使用静态内存分配。这些变量在程序的整个生命周期中都存在&…

创建TextMeshPro字体文件

相比于Unity的Text组件&#xff0c;TextMesh Pro提供了更强大的文本格式和布局控制&#xff0c;更高级的文本渲染技术&#xff0c;更灵活的文本样式和纹理支持&#xff0c;更好的性能以及更易于使用的优点。但unity自带TextMeshPro字体不支持中文。这里使用普通字体文件生成Tex…

React16源码: React中event事件对象的创建过程源码实现

event 对象 1 &#xff09; 概述 在生产事件对象的过程当中&#xff0c;要去调用每一个 possiblePlugin.extractEvents 方法现在单独看下这里面的细节过程&#xff0c;即如何去生产这个事件对象的过程 2 &#xff09;源码 定位到 packages/events/EventPluginHub.js#L172 f…

Spring事件之注解@EventListener讲解

文章目录 1 注解EventListener1.1 示例Demo1.1.1 简单例子1.1.2 解耦1.1.3 Spring事件 1.2 深入EventListener1.2.1 debug调试1.2.2 问题一&#xff1a; Spring是怎么知道要去触发这个方法1.2.3 问题二&#xff1a;ApplicationListenerMethodAdapter1.2.4 问题三&#xff1a;Si…

Vue学习笔记:计算属性

计算属性 入门进阶二次进阶三次进阶四次进阶结界五次进阶六次进阶七次进阶八次进阶九次进阶终章彩蛋 入门 Vue.js中&#xff0c;计算属性示例&#xff1a; export default {data() {return {firstName: John,lastName: Doe};},computed: {// 计算属性&#xff1a;全名fullNam…

(12)喝汽水

文章目录 每日一言题目解题思路一代码 解题思路二代码 结语 每日一言 长风沛雨&#xff0c;艳阳明月。田野被喜悦铺满&#xff0c;天地间充满着生的豪情。 题目 已知1瓶汽水1元&#xff0c;2个空瓶可以换一瓶汽水&#xff0c;输入整数n&#xff08;n>0&#xff09;&#x…

Maven工程的配置及使用

一、Maven章节 Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供构建和依赖管理支持的工具 1.1、maven的作用 1&#xff09;依赖管理&#xff1a; 方便快捷的管理项目依赖的资源包&#xff08;jar包&#xff09;避免版本冲突 2&#xff09;统一项目结构&…

机器学习算法之逻辑回归算法(Logistic Regression)

逻辑回归算法是一种用于分类问题的经典机器学习算法。虽然它的名字中带有“回归”,但实际上逻辑回归用于解决分类问题,特别是二分类问题。本篇博文将详细介绍逻辑回归算法的工作原理、应用领域以及Python示例。 算法背景 逻辑回归起源于20世纪初,用于分析生存率数据。随后…

Android studio打开md无法显示md渲染问题

Where is Android Studio Markdown support plugin preview preference? - Stack Overflow android studio开发无法选择markdown渲染功能的问题 原因是java runtime出了问题 搜索下面功能 Choose Boot Java Runtime for the IDE 选择带JCEF的 可以选最新的java版本 重启之…

Jvm FullGC 如何排查?

使用场景 我们在使用系统时&#xff0c;有时请求和响应会变得特别慢&#xff0c;系统也变得很卡。 有可能是FullGC的问题&#xff0c;可以逐步地进行排查。 使用jps和top确定进程号pid jps可以列出正在运行的jvm进程&#xff0c;并显示jvm执行主类名称( main()函数所在的类…

浙政钉(专有钉钉)

专有钉钉是浙政钉的测试版本&#xff0c;可在正式发布之前进行业务开发。 专有钉钉 原名政务钉钉 是高安全、强管控、灵活开放的面向大型组织专有独享的协同办公平台。支持专有云、混合云等多种方式灵活部署&#xff0c;以满足客户特定场景所需为目标&#xff0c;最大化以“平…

window 镜像---负载篇

前提&#xff1a;需要修改window的powershell执行脚本的策略 步骤&#xff1a;以管理员身份打开powershell&#xff0c;执行 Get-ExecutionPolicy查看当前执行策略&#xff0c;若返回值是Restricted&#xff0c;需执行Set-ExecutionPolicy RemoteSigned powershell 版本信息&am…

.NET Core已经开源好几年了, 为什么不像JVM那样很多人研究和调优其GC算法?

.NET Core的开源确实是微软近年来重要的一步&#xff0c;它不仅标志着.NET生态系统向更开放、更多样化的方向迈进&#xff0c;也为更广泛的社区参与和贡献提供了可能。然而&#xff0c;与JVM相比&#xff0c;研究和调优GC&#xff08;垃圾回收&#xff09;算法的工作似乎没有那…

gif格式图片是怎么做的?教你一招在线转换

常见的图片有jpg、png以及gif格式&#xff0c;其中&#xff0c;jpg和png格式的图片我们一般手机拍摄或是接受的都是这两种格式&#xff0c;但是gif格式的图片我们却需要从网上下载。那么&#xff0c;当我们想要自己制作gif动画的时候要怎么操作呢&#xff1f;只需要使用在线制作…

NDK Could NOT find OpenGL (missing: OPENGL_glx_LIBRARY) Ubuntu

1. update 该命令将安装一堆新包&#xff0c;包括gcc&#xff0c;g 和make。 sudo apt-get update sudo apt-get install -y build-essential2. install OpenGL依赖库 sudo apt-get install freeglut3-dev sudo apt-get install libgl1-mesa-dev sudo apt-get install libxt-…

MAE实战:使用MAE提高主干网络的精度(一)

摘要 MAE已经出来有几年了&#xff0c;很多人还不知道怎么去使用&#xff0c;本文通过两个例子说明一下。分两部分&#xff0c;一部分介绍一个简单的例子&#xff0c;让大家了解MAE训练的流程。一部分是一个新的模型&#xff0c;让大家了解如何将自己的模型加入MAE。 论文标…

【BBF系列协议】TR156 在TR101环境中使用GPON Access

TR-156 在TR-101环境中使用GPON Access 执行摘要 TR-101提供了一种基于以太网的体系结构,它已成为针对使用DSL作为宽带接入技术的住宅和企业客户的三联游戏部署的全球标准。然而,许多TR-101的体系结构规范都是与访问无关的,而且它们今天也与其他访问技术一起被广泛使用,特…