C【动态内存管理】
1. 为什么存在动态内存分配

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

2. 动态内存函数的介绍
2.1 malloc:stdlib.h
void* malloc (size_t size);
int* p = (int*)malloc(40);

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>int main()
{//向内存申请10个整形的空间int* p = (int*)malloc(40);if (p == NULL){//打印错误原因的一个方式printf("%s\n", strerror(errno));}else{//正常使用空间int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;}for (i = 0; i < 10; i++){printf("%d ", *(p + i));}}//当动态申请的空间不再使用的时候//就应该还给操作系统free(p);//上面是将p断开,但是实际上p还是存储内容,所以我们手动设置为nullp = NULL;return 0;
}
2.2 free:stdlib.h
是用来做动态内存的释放和回收的
注意点:free(str)后,实际上str还执行一个空的地址,所以此时str!=NULL
void free (void* ptr);

2.3 calloc
calloc 函数也用来动态内存分配。可以初始化空间。
void* calloc (size_t num, size_t size);
int*p = (int*)calloc(10, sizeof(int));
int main()
{//malloc(10*sizeof(int))int*p = (int*)calloc(10, sizeof(int));if (p == NULL){printf("%s\n", strerror(errno));}else{int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(p + i));}}//释放空间//free函数是用来释放动态开辟的空间的free(p);p = NULL;return 0;
}

2.4 realloc
当初始申请空间不够,这时使用realloc开辟新的空间【调整动态开辟内存空间的大小】

使用注意点:
1. 如果p指向的空间之后有足够的内存空间可以追加,则直接追加,后返回p
2. 如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存区域
开辟一块满足需求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间
最后返回新开辟的内存空间地址
3. 得用一个新的变量来接受realloc函数的返回值

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


#include <stdio.h>
int main()
{int *ptr = (int*)malloc(100);if(ptr != NULL){//业务处理}else{exit(EXIT_FAILURE); }//扩展容量//代码1ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)//代码2int*p = NULL;p = realloc(ptr, 1000);if(p != NULL){ptr = p;}//业务处理free(ptr);return 0;
}
3. 常见的动态内存错误
3.1 对NULL指针的解引用操作
//1. 对NULL进行解引用操作int *p = (int*)malloc(40);//万一malloc失败了,p就被赋值为NULL//所以我们在申请完一块空间之后,一定要进行判空操作*p = 0;//errint i = 0;for (i = 0; i < 10; i++){*(p + i) = i;//err}free(p);p = NULL;
3.2 对动态开辟空间的越界访问
//2. 对动态开辟的内存的越界访问int *p = (int*)malloc(5 * sizeof(int));if (p == NULL){return 0;}else{int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;}}//free(p);p = NULL;
3.3 对非动态开辟内存使用free释放
//栈区开辟出来的,不是动态开辟int a = 10;int* p = &a;*p = 20;//3. 对非动态开辟内存的freefree(p);p = NULL;return 0;
3.4 使用free释放一块动态开辟内存的一部分
int*p = (int*)malloc(40);if (p == NULL){return 0;}int i = 0;for (i = 0; i < 5; i++){*p++ = i;}//回收空间// 使用free释放动态开辟内存的一部分free(p);p =NULL;

3.5 对同一块动态内存多次释放
int *p = (int*)malloc(40);if (p == NULL){return 0;}//使用//释放free(p);//将p设置为空指针,可以防止重复释放产生的错误p = NULL;
3.6 动态开辟内存忘记释放(内存泄漏)
while (1){malloc(1);}

4. 几个经典的笔试题
4.1 题目1:

//面试1:
void GetMemory(char *p)
{p = (char *)malloc(100);
}void Test(void)
{char *str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}int main()
{Test();char*str = "abcdef";printf("%s\n", str);printf(str);printf("abcdef");return 0;
}
修改结果
void GetMemory(char **p)//**p:是p的地址
{//*p:是p的内容*p = (char *)malloc(100);
}void Test(void)
{char *str = NULL;GetMemory(&str);//传地址strcpy(str, "hello world");printf(str);free(str);str = NULL;
}int main()
{Test();return 0;
}
char* GetMemory(char *p)
{p = (char *)malloc(100);//将p传递除去return p;
}void Test(void)
{char *str = NULL;str = GetMemory(str);strcpy(str, "hello world");printf(str);free(str);str = NULL;
}int main()
{Test();return 0;
}
4.2 题目2:


【存储在栈区中的数据,出了函数则就会被销毁】
//面试2
char *GetMemory(void)
{char p[] = "hello world";//局部变量//跳出此函数,则p被销毁return p;
}void Test(void)
{char *str = NULL;str = GetMemory();//此时str的p的地址printf(str);//非法地址访问,故输出随机值
}int main()
{Test();return 0;
}
【数据存储在静态区(static),出了函数数据还是存在】
//在静态区,出了函数还是可以继续使用
int* test()
{//使用static,将a放入静态区,出了这个函数,内存并没有被销毁,故在外面还可以访问到static int a = 10;//静态区int a = 10;//栈区 return &a;
}int main()
{int*p = test();//此时p接收到a的地址*p = 20;//将a修改为20return 0;//20
}
【数据存储在堆区,出了函数数据还是存在】
//在堆区,出函数还是存在
int* test()
{int *ptr = malloc(100);//堆区return ptr;
}int main()
{int *p = test();return 0;
}
4.3 题目3:

void GetMemory(char **p, int num)
{*p = (char *)malloc(num);//给p创建100个新的char
}
void Test(void)
{char *str = NULL;GetMemory(&str, 100);strcpy(str, "hello");//可以输出printf(str);//改:忘记free内容,导致内存泄露free(str);str = NULL;
}
4.4 题目4:

void Test(void)
{char *str = (char *)malloc(100);strcpy(str, "hello");free(str);//free了但是没有把指针置为null//此处的问题:已经释放的空间,还被使用if (str != NULL)//则此时str还不为NUll,则进入判断{strcpy(str, "world");printf(str);}
}int main()
{Test();//worldreturn 0;
}
解决:
void Test(void)
{char* str = (char*)malloc(100);strcpy(str, "hello");free(str);//解决:将str置为NULLstr = NULL;if (str != NULL){strcpy(str, "world");printf(str);}
}int main()
{Test();//worldreturn 0;
}
5. C/C++程序的内存开辟

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

6. 柔性数组
结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。

struct S
{int n;int arr[10];
};struct S
{int n;int arr[];//未知大小的
};struct S
{int n;int arr[0];//未知大小的-柔性数组成员-数组的大小是可以调整的
};
6.1 柔性数组的特点:
- 结构中的柔性数组成员前面必须至少一个其他成员。
- sizeof 返回的这种结构大小不包括柔性数组的内存。
- 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大 小,以适应柔性数组的预期大小。
//代码1
int i = 0;
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
//业务处理
p->i = 100;
for(i=0; i<100; i++)
{p->a[i] = i;
}
free(p);
6.2 柔性数组的使用--int[] a

struct S
{int n;int arr[0];//未知大小的-柔性数组成员-数组的大小是可以调整的
};int main()
{struct S s;printf("%d\n", sizeof(s));////sizeof(struct S):不包括int arr的大小//5*sizeof(int):手动的给arr赋值struct S* ps = (struct S*)malloc(sizeof(struct S)+5*sizeof(int));ps->n = 100;int i = 0;for (i = 0; i < 5; i++){ps->arr[i] = i;//0 1 2 3 4}//开辟内存struct S* ptr = realloc(ps, 44);if (ptr != NULL){ps = ptr;}for (i = 5; i < 10; i++){ps->arr[i] = i;}//打印arr所有数值for (i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}//释放free(ps);ps = NULL;return 0;
}
6.3 柔性数组的扩展:int* arr

struct S
{int n;int* arr;
};
int main()
{//sizeof(struct S):此时包括int* arrstruct S* ps = (struct S*)malloc(sizeof(struct S));//再一次给arr创建动态内存ps->arr = malloc(5 * sizeof(int));int i = 0;for (i = 0; i < 5; i++){ps->arr[i] = i;}for (i = 0; i < 5; i++){printf("%d ", ps->arr[i]);}//调整大小int* ptr = realloc(ps->arr, 10 * sizeof(int));if (ptr != NULL){ps->arr = ptr;}for (i = 5; i < 10; i++){ps->arr[i] = i;}for (i = 0; i < 10; i++){printf("%d ", ps->arr[i]);}//释放内存:注意释放顺序free(ps->arr);ps->arr = NULL;free(ps);ps = NULL;return 0;
}
6.4 int arr[0] 和 int* arr的区别
上述 代码1 和 代码2 可以完成同样的功能,但是 方法1 的实现有两个好处:

相关文章:
C【动态内存管理】
1. 为什么存在动态内存分配 int val 20;//在栈空间上开辟四个字节 char arr[10] {0};//在栈空间上开辟10个字节的连续空间 2. 动态内存函数的介绍 2.1 malloc:stdlib.h void* malloc (size_t size); int* p (int*)malloc(40); #include <stdlib.h> #incl…...
Javase | 集合-上
目录: 一、集合:1.集合的概述2.集合的分类 二、“单个方式”存储元素:1.Collection1.1 Collection的概述1.2 Collection接口中常用的方法Iterator<T> iterator( ) 1.3 Collection下的子接口 2.Iterable:2.1 Iterable的概述2…...
Multitor:一款带有负载均衡功能的多Tor实例创建工具
关于Multitor Multitor是一款带有负载均衡功能的多Tor实例创建工具,Multitor的主要目的是以最快的速度完成大量Tor进程的初始化,并将大量实例应用到我们日常使用的程序中,例如Web浏览器和聊天工具等等。除此之外,在该工具的帮助下…...
AIGC专栏6——通过阿里云与AutoDL快速拉起Stable Diffusion和EasyPhoto
AIGC专栏6——通过阿里云与AutoDL快速拉起Stable Diffusion和EasyPhoto 学习前言Aliyun DSW快速拉起(新用户有三个月免费时间)1、拉起DSW2、运行Notebook3、一些小bug AutoDL快速拉起1、拉起AutoDL2、运行Notebook 学习前言 快速拉起AIGC服务 对 用户体…...
Mysql的逻辑架构、存储引擎
1. 逻辑架构剖析 1.1 服务器处理客户端请求 首先MySQL是典型的C/S架构,即Clinet/Server 架构,服务端程序使用的mysqld。 不论客户端进程和服务器进程是采用哪种方式进行通信,最后实现的效果是:客户端进程向服务器进程发送一段文…...
[ES6]模块
[ES6]模块 特点export 与 import基本用法导入导出基本方式导入导出等价方式html 导入 别名导出默认导出基本用法默认导出对象 复合使用import 命令的特点只读属性单例模式静态执行特性 在 ES6 前, 实现模块化使用的是 RequireJS 或者 seaJS(分别是基于 AMD 规范的模…...
物联网终端算法
物联网终端算法是指在物联网终端设备上运行的各种算法,包括数据采集、数据预处理、数据传输、数据存储、数据处理、数据分析等算法。以下是物联网终端算法的一些具体应用: 数据采集算法:用于采集各种传感器数据,包括温度、湿度、气…...
【面试刷题】——TCP三次握手,以及为什么要三次握手
TCP(传输控制协议)的三次握手是建立TCP连接的过程,它确保了通信双方的正常启动和参数协商。三次握手的过程如下: 客户端发送请求: 客户端首先向服务器发送一个特殊的TCP报文,称为SYN(同步&…...
算法系列-力扣206-单链表反转
题目说明 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 方法一:头插法反转链表 思路: 声明p指针指向原头节点,并将头节点置空;p指针循环原链表将元素用头节点插入法逐个插入head中&…...
网络基础-应用层协议-HTTP/HTTPS
HTTP/HTTPS HTTP基本概念协议格式请求报文请求方法请求资源地址协议版本 应答报文 常见Header常见状态码与状态描述Cookie&Sessionhttp协议特点 HTTPS基本概念对称加密与非对称加密数据摘要&数据指纹HTTPS工作过程探究只采用对称加密只采用非对称加密双方都采用非对称加…...
problen(5)ubuntu版本问题
浅浅记录一下这段时间的血和泪吧,大概耗时快一个月了吧,终于解决了...... 因为需要开启pwn之旅,需要在Ubuntu上安装一些东西,就是下面的一条命令: sudo pip3 install pwntools -i Simple Index(显示不太好了…...
写一篇nginx配置指南
nginx.conf配置 找到Nginx的安装目录下的nginx.conf文件,该文件负责Nginx的基础功能配置。 配置文件概述 Nginx的主配置文件(conf/nginx.conf)按以下结构组织: 配置块功能描述全局块与Nginx运行相关的全局设置events块与网络连接有关的设置http块代理…...
rhel8防火墙firewalld操作
1.查看默认区域 [rootlocalhost r]# firewall-cmd --get-default-zone public2.查看网卡关联的区域 [rootlocalhost r]# firewall-cmd --get-zone-of-interfaceifcfg-ens160 external 3.设置网卡的默认区域修改为work [rootlocalhost r]# firewall-cmd --zonework --change…...
OpenCV项目实战(2)— 如何用OpenCV实现弹球动画
前言:Hello大家好,我是小哥谈。OpenCV能够在画布上绘制静态的图形,例如,线段、矩形、正方形、圆形、多边形、文字等。那么,能不能让这些静态的图形移动起来?如果能,又该如何编写代码呢ÿ…...
golang iris框架 + linux后端运行
go mod init myappgo get github.com/kataras/iris/v12latestpackage mainimport "github.com/kataras/iris/v12"func main(){app : iris.New()app.Listen(":port") }打包应用 go build main.go开启服务 #nohup ./程序名称 nohup ./main关闭后台 #ps -e…...
linux shell操作- 02 常用命令及案例
文章目录 常用命令 续 常用命令 续 定时任务 通过文本编辑cron任务,实现定时操作 分 小时 天 月 星期 绝对路径sh or cmd* 表示每个xxx,如每个小时每小时的第三分钟执行cmd-> 03 * * * * /home/lauf/scraw.sh每天的第5、8个小时执行-> 00 5,8 * *…...
考研408 | 【计算机组成原理】 数据的表示和运算
进位计数制 十进制计数法: 推广:r进制计数法 任意进制-->十进制: 二进制<-->八进制、十六进制: 各种进制的常见书写方式: 十进制-->任意进制: 十进制-->二进制(拼凑法ÿ…...
【小沐学NLP】AI辅助编程工具汇总
文章目录 1、简介2、国内2.1 aiXcoder2.1.1 工具特点2.1.2 部署方式2.1.3 使用费用2.1.4 代码测试2.1.4.1 代码搜索引擎2.1.4.2 在线体验 2.2 CodeGeeX2.2.1 工具特点2.2.2 部署方式2.2.3 使用费用2.2.4 代码测试 2.3 Alibaba Cloud AI Coding Assistant(cosy&#…...
linux动态扩容系统盘(非lvm磁盘)
查看磁盘状态 执行df -Th查看磁盘情况 [rootiotdbtest1 ~]# df -Th Filesystem Type Size Used Avail Use% Mounted on devtmpfs devtmpfs 7.7G 0 7.7G 0% /dev tmpfs tmpfs 7.7G 0 7.7G 0% /dev/shm tmpfs tmpfs …...
Gitlab仓库部署
Gitlab仓库部署 一、Gitlab的概述1、gitlab介绍2、gitlab主要功能3、gitlab和github的区别 二、部署环境1、安装依赖环境2、安装Postfix邮箱3、Gitlab优势4、Gitlab工作流程 三、Gitlab部署过程1、Yum安装Gitlab2、配置gitlab站点URL3、启动并访问Gitlab 四、Gitlab具体操作1、…...
Kerberos身份认证原理与企业级排错实战指南
1. 这不是“另一个登录框”,而是一套精密运转的身份验证齿轮系统很多人第一次听说 Kerberos,是在公司内网登录邮箱或访问内部系统时,看到那个带小盾牌图标的弹窗——“正在使用 Kerberos 协议进行身份验证”。于是下意识觉得:“哦…...
如何进行TVA仿真引擎的“光照地狱”训练?
重磅预告:本专栏将独家连载系列丛书《智能体视觉技术与应用》部分精华内容,该书是世界首套系统阐述“因式智能体”视觉理论与实践的专著,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“…...
终极免费音乐解锁工具:5步轻松解密你的加密音乐文件
终极免费音乐解锁工具:5步轻松解密你的加密音乐文件 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址: https:/…...
BiliBiliCCSubtitle终极指南:5个实战技巧高效下载B站字幕
BiliBiliCCSubtitle终极指南:5个实战技巧高效下载B站字幕 【免费下载链接】BiliBiliCCSubtitle 一个用于下载B站(哔哩哔哩)CC字幕及转换的工具; 项目地址: https://gitcode.com/gh_mirrors/bi/BiliBiliCCSubtitle 还在为无法保存B站视频字幕而烦恼࿱…...
ArduPilot飞行模式实战:从代码角度看Stabilize、Acro、Loiter模式如何切换(附避坑指南)
ArduPilot飞行模式深度解析:从状态机到实战避坑指南 在开源飞控领域,ArduPilot以其强大的飞行模式系统著称。不同于普通用户只需了解模式功能,开发者更需要掌握模式切换的底层机制——这直接关系到飞行安全与二次开发效率。本文将带您深入Sta…...
树莓派Zero离线语音交互实战:TTS与STT引擎部署与优化
1. 项目概述:为什么选择树莓派 Zero 来实现语音功能?如果你玩过 Arduino、ESP32 这类微控制器,也接触过树莓派 4B 这样的单板电脑,那你大概能理解那种“选择困难症”:微控制器实时性强、功耗低,但算力有限&…...
为什么你明明很努力,领导却总看不到?问题出在这
许多测试同行在深夜加班排查Bug时,在凌晨赶写自动化脚本时,在对着海量数据做性能分析时,内心都会浮现一个共同的困惑:我明明已经这么拼了,为什么在领导眼里,我依然是个“找茬的”,而不是“创造价…...
LeetCode 80 · 删除有序数组中的重复项 II:通用模板的威力
LeetCode 26 要求每个元素最多出现一次,这道题放宽到最多出现两次。看起来只是把 1 改成了 2,但这个"小改动"背后藏着一个通用的快慢指针模板——把 2 换成任意整数 m,代码几乎不用动。这就是模板的威力:改一个数字&…...
MFCC与可解释机器学习:构建可解释的L2发音AI诊断系统
1. 项目概述:当语音技术遇见二语教学 作为一名在语音技术和教育技术交叉领域摸爬滚打了十多年的从业者,我常常思考一个问题:我们能用算法“听”出一个人说外语时,他的母语口音吗?更进一步,我们能否不仅“听…...
音乐解锁工具终极指南:3分钟掌握加密音乐解密技巧
音乐解锁工具终极指南:3分钟掌握加密音乐解密技巧 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址: https://g…...


