手把手教玩转你动态内存管理(InsCode Stable Diffusion 美图活动一期)

news/2024/10/20 15:46:48/

目录https://inscode.csdn.net/@inscode/Stable-Diffusion

一、动态内存管理的意义

二、动态内存管理函数

1.malloc和free

1.1认识malloc和free

1.2malloc和free的作用

1.3使用malloc和free时应注意的事项

1.3.1使用malloc注意事项

1.3.2使用free注意事项

1.4使用free和malloc函数

2.calloc

2.1认识calloc

2.2calloc的作用

2.3使用calloc

3.realloc

3.1认识realloc

3.2realloc的用法

3.3realloc函数扩大空间的多种情况

3.4使用realloc

三、柔性数组

1.柔性数组的特点:

2.柔性数组的开辟和使用

3.指针可以替代柔性数组的作用

4.柔性数组的优势


一、动态内存管理的意义

在我们敲代码的时候,是否会有着这样的想法,为什么我创建的这个数组arr[10]它就只能存储10个元素呢,它为什么不能在程序的运行时跟随我们的需要,扩大它对应的空间呢?这样子不仅能够节省不必要的浪费,而且能够随着我们的需求弹性地满足我们。可能有的小伙伴不是很理解为什么会造成浪费,举个例子,我有一个能存放100个整型的数组,但我只放了10个元素进去,但计算机它已经把这400个字节的空间分配给了这个数组,这400个字节的空间在这个数组销毁之前,也就是走出它的生命周期前,这400字节的空间只能它用,别人都用不了,这就造成了浪费,

二、动态内存管理函数

1.malloc和free

这两个函数,分开来讲太割裂了,于是这里笔者就把它们放在一起

1.1认识malloc和free

关于函数定义的图片均出自cplusplus.com - The C++ Resources Network

从返回类型来看,malloc的返回类型是空指针,也就是说我们在接收它的时候很可能要用到强制类型转换,从参数来看,是一个无符号整型

从返回类型来看free的返回类型为空类型,也就是说,free不返回任何值回来,不可使用链式法则,从参数来看,是个无类型的指针

1.2malloc和free的作用

malloc函数的作用是分配所需的内存空间,并返回一个指向它的空类型的指针,这个内存空间的大小跟你传给它的参数大小一致,注意:开辟空间的单位是字节。

free的用法则是释放之前申请的动态内存空间,注意,是动态内存空间,也就是说,free只能释放动态内存函数开辟的空间

1.3使用malloc和free时应注意的事项

1.3.1使用malloc注意事项

malloc申请下来的空间,只有两种情况会返回给操作系统,第一种就是程序结束了,第二种就是程序设计者在用完这个malloc申请下来的空间后使用free将其释放掉了。有联想能力的小伙伴恐怕就想到了,那如果我写了个循环一直在开辟空间,且我通过特殊的方式让程序无法结束,那是否会占用计算机的大量内存,是的,这可能会使计算机没法正常工作。因此,在使用malloc的时候我们应该秉承着用完就释放的原则      这样不仅能大大提高计算机的工作效率,还能增加内存空间的利用率。还应注意的一点,那便是malloc函数开辟空间是有可能失败的   毕竟计算机的空间不是无穷无尽的,当你开辟的空间过大时,计算机没法提供,就malloc就会返回一个空指针(NULL)

1.3.2使用free注意事项

(1)不要对同一块空间多次释放,因为当你释放完这一块当时开辟的空间后,后面经过一系列的操作,计算机可能已经把这一块空间使用到了,而你又对它进行了一次释放,很可能就会出现未知的问题。

(2)free只能够释放动态内存函数开辟的空间

(3)使用free释放一部分动态内存空间也是有问题的。什么是只释放一部分,上个代码你就知道了

#include<stdio.h>
#include<stdlib.h>
int main()
{int* a = (int*)malloc(100);//创建1个大小为100个字节的空间,并用a来接收a++;//改变地址,使其指向首地址的下一个地址free(a);//不再指向动态内存的起始地址,还有一个字节没被释放
}

1.4使用free和malloc函数

#include<stdio.h>
#include<stdlib.h>//malloc,free所在的头文件
int main()
{int* a = NULL;//初始化指针int num = 0;printf("你想要一个多大的数组\n");scanf("%d", &num);a= (int*)malloc((sizeof(int)) * num);//malloc返回的值类型为无符号指针,因此在用a接收的时候需要将其强制类型转换为同一类型int i = 0;if (a == NULL)//避免开辟空间失败{perror("malloc");//perror函数的作用是提示你所犯的错误return 0;//开辟空间失败,中止程序}for (i = 0; i < num; i++){a[i] = i;//以数组的方式给开辟的内容赋值}for (i = 0; i < num; i++){printf("%d ", a[i]);//打印出数组内容if ((i+1)% 10 == 0)//没10个换一次行,美观{printf("\n");}}free(a);//使用free释放掉之前申请的空间a = NULL;//此时a是野指针,因此将a重新变为空指针,避免后面再使用的时候出现问题
}

开辟成功: 

 开辟失败:

2.calloc

2.1认识calloc

 calloc函数的返回类型为空指针   因此在接收它的时候我们应该要使用强制类型转换才能接受   有两个参数,均是无符号整型

2.2calloc的作用

calloc的作用是开辟num个size大小的动态内存空间,并将里面的内容初始化为0  从这里看,它与malloc的作用几乎是一模一样,只是多了一步将内容初始化为0,不过讲真的,即使calloc不比malloc多这一步,我也更愿意使用calloc而不是malloc,因为calloc函数的两个参数可以让你很好的知道你当时开辟这个空间的用途,可以大大提高代码的可读性。注意:开辟空间的单位一样是字节

2.3使用calloc

#include<stdio.h>
#include<stdlib.h>
int main()
{int* a = (int*)calloc(100,sizeof(int));//创建了一个大小为100个整型的空间,并用a来接收if (a == NULL)//避免开辟失败{perrof("calloc");//报相应错误return 0;//开辟失败,中止程序}free(a);//释放开辟的空间a = NULL;//a现在是野指针,将其变为空指针
}

3.realloc

3.1认识realloc

realloc函数的返回类型为空指针,因此我们在接收它返回的地址时要用到强制类型转换,将其转换为我们需要的类型。realloc函数有两个参数,一个是无类型的指针变量,一个是无符号整型

3.2realloc的用法

realloc可以对给定指针所给的空间进行扩大或缩小   ptr为你所给的指针,size为目标空间被操作完后的大小。这个函数调整完大小之后会将之前在这个空间里存储的数据再存放到这个新的空间,当然如果你是缩小空间的话,可能会出现数据丢失。注意:扩大或缩小空间的大小的单位也是字节

3.3realloc函数扩大空间的多种情况

情况1:

以这张图来举例,假设我已经开辟了100个字节的空间,后面剩余的空间已经只剩下50个,而我现在想要再开辟30个字节的空间,也就是将原来100个字节的空间扩大到130个字节。而realloc一看,后面还有50呢,随便开辟,没事,大方的很,那么此时就会直接在原有数据之后直接追加

情况2:

那么假设我想把这100个字节的空间开辟成200个字节的怎么办呢,realloc一看,后面的空间不够大了啊,总共就150㎡的房子,给你住满了,realloc总不可能把隔壁人家的房子给你敲掉让你住不是,它只能够再给你找你个新的更大的房子,也就是在内存中寻找到足够的空间,重新开辟一个空间给你,而之前的旧的空间它会自动帮你释放掉,不用手动释放

情况3:

计算机内存不够,不能开辟这么大的空间,那就会开辟失败,返回一个空指针给你。

3.4使用realloc

#include<stdio.h>
#include<stdlib.h>
int main()
{int*a=(int*)malloc(100);int num = 0;printf("修改之前a的地址%p\n", a);printf("你要多大的空间\n");scanf("%d", &num);//输入想要的空间大小a=realloc(a,num);if (a == NULL)//避免开辟失败{perror("realloc");//报错return 0;//中止程序}printf("修改成功,a的地址为%p\n",a);free(a);//释放开辟的空间a = NULL;//a此时是野指针,安全起见,给它变为空指针
}

后面的空间充足,地址不变

 后面的空间不足,地址改变

 计算机没法给那么大的空间

三、柔性数组

顾名思义,柔性数组就是可以变换大小的数组,在c++上面数组可以传变量,而在c上数组只能传常量,我们要怎么开辟柔性数组呢?

1.柔性数组的特点:

(1)开辟的数组前至少要有一个结构体成员

(2)sizeof计算柔性数组所在的结构体时,柔性数组不会被计算在其中

(3)包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

2.柔性数组的开辟和使用

#include<stdio.h>
#include<stdlib.h>
//struct abc
//{
//	int a;
//	int b[0];
//};
struct abc
//有的编译器只能够使用上面的方法,但这两个至少有一个可以
{int a;int b[];
};
int main()
{struct abc* x = NULL;x = (struct abc*)malloc(sizeof(struct abc) + 40);//创建一个字节数为40即10个字节的数组if (x == NULL){perror("malloc");//报错提示return 0;}int i = 0;for (i = 0; i < 10; i++){x->b[i] = i;//将可以存放10个元素的数组初始化}for (i = 0; i < 10; i++){printf("%d ", x->b[i]);//打印出来}x = realloc(x,104);//4个字节的空间是给a的,100个字节的空间是给b的,25个字节if (x == NULL){perror("realloc");//报错提示return 0;}printf("\n");for (i = 0; i < 25; i++){x->b[i] = i;//将可以存放25元素的数组初始化}for (i = 0; i < 25; i++){printf("%d ", x->b[i]);//打印出来}free(x);//释放x的空间x = NULL;//将野指针置为空指针,避免在后面使用
}

 

3.指针可以替代柔性数组的作用

#include<stdio.h>
#include<stdlib.h>
struct abc
{int a;int *b;//通过指针实现柔性数组
};
int main()
{struct abc* x = NULL;x = (struct abc*)malloc(sizeof(struct abc));if (x == NULL){perror("malloc");//报错提示return 0;}x->b=malloc(40);if (x == NULL){perror("malloc");//报错提示return 0;}int i = 0;for (i = 0; i < 10; i++){	x->b[i]= i;//将可以存放10个元素的数组初始化}for (i = 0; i < 10; i++){printf("%d ", x->b[i]);//打印出来}printf("\n");x->b=realloc(x->b, 60);if (x->b==NULL){perror("realloc");//报错提示return 0;}for (i = 0; i < 15; i++){x->b[i] = i;//将可以存放15个元素的数组初始化}for (i = 0; i < 15; i++){printf("%d ", x->b[i]);//打印出来}free(x->b);x->b = NULL;free(x);x = NULL;
}

4.柔性数组的优势

方便内存释放,用指针得两次,柔性数组一次就搞定。访问速度快,因为空间连续。

好了,今天的分享就到这里结束了,感谢各位友友的来访,祝各位友友前程似锦O(∩_∩)O


http://www.ppmy.cn/news/892689.html

相关文章

github进不去的解决办法

github就凭运气进吧&#xff0c;偶尔能进去。 介绍几个可以快速进的办法&#xff1a; 第一个&#xff0c;安装插件&#xff1a;&#xff08;在microsoft搜索watt toolkit插件并安装&#xff09; 然后勾选github选项&#xff1a; 接着返回你github网站就可以了。 第二个&#…

【Python爬虫案例学习8】python爬取淘宝里的手机报价并以价格排序

第一步&#xff1a; 先分析这个url&#xff0c;”&#xff1f;“后面的都是它的关键字&#xff0c;requests中get函数的关键字的参数是params&#xff0c;post函数的关键字参数是data&#xff0c; 关键字用字典的形式传进去&#xff0c;这样我们就可以自己改关键字去搜索别的…

linux centos7 静默安装 oracle 11g,【亲测有效】,包含远程连接、提供安装包

Centos7 安装oracle11g 环境准备 操作系统 centos7 oracle版本 oracle11g 终端软件 MobaXterm 192.168.46.61 oracleMaster 安装包 网盘地址 一、安装前准备 1、关闭selinux [rootoracleMaster ~]# vim /etc/selinux/config修改 SELINUX 为 disabled # This file controls …

Django实现简单的音乐播放器 4

在原有音乐播放器功能基础上&#xff0c;增加上传音乐功能。 效果&#xff1a; 目录 配置上传路径 配置路由 视图处理歌曲 引入类库 保存歌曲文件 模板上传 设置菜单列表 设置菜单列表样式 脚本设置 上传效果 1.显示菜单列表 2.点击上传歌曲 3.上传完成 4.查看保…

Html5视频video标签中调用blob地址,实现视频安全

Html5视频video标签中调用blob地址&#xff0c;实现视频安全 后端代码参考&#xff1a; /** 在这里可以进行权限验证等操作*///创建文件对象 File f new File("E:\\test.mp4"); //获取文件名称 String fileName f.getName(); //导出文件 String agent getRequest…

Html5视频video标签中使用blob实现视频播放加密

后端代码&#xff1a; /** 在这里可以进行权限验证等操作*///创建文件对象 File f new File("E:\\test.mp4"); //获取文件名称 String fileName f.getName(); //导出文件 String agent getRequest().getHeader("User-Agent").toUpperCase(); InputStre…

Google技巧:crack web sites

首先打开Google&#xff0c;在关键词输入框中输入"index of/"inurl:lib(双引号为英文状态下&#xff09;&#xff0c;选择“搜索简体中文网页”选项&#xff0c;回车搜索&#xff0c;得到了一些网页&#xff0c;不要以为这是一些普通的页面&#xff0c;其实它们是一些…

Android视频播放项目总结之 使用第三方Vitamio库,开发万能播放器(一)

Android自身代的vodeoView可以实现视频播放,但是很格式不支持 万能播放器指的是能任何格式的视频,他要用到第三方的库: ffmpeg开源框架 vitamio基于ffmpeg开发的开源框架 我们的开发用的是vitamio开源框架可以在官网上下载 Vitamio 是什么? Vitamio 是一款 Android与 …