动态内存管理续(c++方向必看)

发布时间:2026/10/5 10:27:36

动态内存管理续(c++方向必看) 引言上一篇文章主要介绍了动态内存的函数和基本用法。https://blog.csdn.net/2301_81479880/article/details/166902312?fromshareblogdetailsharetypeblogdetailsharerId166902312sharereferPCsharesource2301_81479880sharefromfrom_link本文主要是运用动态内存开辟的一些注意事项典型错误经典例题和柔性数组。学好动态内存管理对于后续的学习数据结构是很有帮助的。目录1.常见的动态内存错误1.1对NULL指针的解引用操作1.2对动态内存空间的越界访问1.3对非动态开辟的内存使用free1.4使用free释放一块动态内存开辟的一部分1.5对同一块动态内存多次释放1.6动态开辟内存忘记释放内存泄漏2.动态内存管理经典笔试题2.1第一题2.2第二题2.3第三题3.柔性数组3.1柔性数组的特点3.2柔性数组的使用3.3柔性数组的优势1.常见的动态内存错误1.1对NULL指针的解引用操作void test() { int* p (int*)malloc(INT_MAX / 4); *p 20;//如果pd的值是NULL就会出问题 free(p); }使用malloc开辟内存失败时返回值为NULL如果不加判读直接使用程序就会崩溃所以在使用完malloc后及时判断如果p不为空程序才能继续使用。1.2对动态内存空间的越界访问void test() { int i 0; int* p (int*)malloc(10 * sizeof(int)); if (NULL p) { return 1; } for (i 0; i 10; i) { *(p i) i;//当i为10时越界访问 } free(p); }动态开辟的空间也是有自己使用范围的超出这个范围就会越界访问程序错误。1.3对非动态开辟的内存使用freevoid test() { int a 10;///局部变量创建在栈区上 int* p a; free(p); }如果我们不信邪头铁尝试一下程序直接就崩溃了我们上一篇文章讲了free函数用来释放动态开辟的内存但是局部变量int是创建在栈区强行使用free释放程序就会崩溃。1.4使用free释放一块动态内存开辟的一部分int main() { int* p (int*)calloc(5, sizeof(int)); if (p NULL)//开辟失败时返回NULL时 { perror(use malloc);//打印错误信息 return 1; } //使用空间 int i 0; for (i 0; i 5; i) { *p i 1; p; } //释放内存 free(p);//这里的p不再是起始位置 p NULL; return 0; }程序执行完后p指向的是下标4或者是指向中间位置这个时候使用free5个字节程序也会崩溃所以释放空间时一定要让p指向起始位置。1.5对同一块动态内存多次释放void test() { int* p (int*)malloc(100); free(p); //解决办法 p NULL把p置为空 free(p);//重复释放 }同一块空间只能释放一次吗重复释放程序就会报错如果我们养好良好的代码习惯每次释放完空间后把p置NULL后面的free就不会生效了。1.6动态开辟内存忘记释放内存泄漏void test() { int* p (int*)malloc(100);//开辟了100字节的空间 if (NULL ! p) { *p 20; } } int main() { test(); while (1);//死循环 return 0; }当动态开辟的空间忘记释放时别人是无法使用这块空间的这就造成了内存泄露注意动态开辟的空间一定要以正确的方法释放如果不释放也要交代清楚你在代码中进行了动态内存分配记得释放。小结1.动态申请的内存空间可以使用free直接释放。2.如果没有使用free释放在程序结束时这个内存也会被操作系统回收。2.动态内存管理经典笔试题2.1第一题#include stdio.h #include stdlib.h #include string.h 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(); return 0; }这个代码能运行吗我们可以看到程序的返回值不是0说明程序在运行中就崩溃了。解析C 语言只有值传递。调用GetMemory(str)时传给形参p的是str的一份拷贝p和str是两个不同的变量。所以strcpy(NULL, hello world)就是往地址 0 写数据属于未定义行为通常表现为段错误。顺带一提那块 100 字节的内存在函数返回后就没人持有它的地址了同时造成内存泄漏。注意hello world连结尾\0共 12 字节100 字节本身够用这里不是越界问题而是指针根本没被赋值。2.2第二题char* GetMemory(void) { char p[] hello world; return p; } void Test(void) { char* str NULL; str GetMemory(); printf(str); } int main() { Test(); return 0; }这个代码正确吗运行结果是什么解析创建char*类型的str并初始化为NULLGetMemory函数中返回了p的地址假设为0x12ff48由str接收现在str中存放的就是0x12ff48可以通过地址打印数组hello world。看起来没有问题但是数组p是局部变量它的生命周期只在GetMemory函数中出了函数它就被释放掉了所以str接收的其实是一个已经释放掉的空间此时它就成为了野指针强行打印就是非法访问结果是一堆乱码。2.3第三题#include stdio.h #include stdlib.h #include string.h void Test(void) { char* str (char*)malloc(100); strcpy(str, hello); free(str); if (str ! NULL) { strcpy(str, world); printf(str); } } int main() { Test(); return 0; }解析经典错误free了之后再次使用动态开辟的空间ree(str)释放的是那块堆内存str这个变量本身不受任何影响它依然保存着原来的地址所以if (str ! NULL)永远为真这个判断毫无意义反而给了人一种已经检查过、很安全的错觉。随后往已经回收的空间内写数据如果这块空间已经分配出去了会破坏别人的数据但也有可能还没有分配出去程序正常跑完。当我们free完成后将str置为NULL程序就没有问题了。3.柔性数组在c99中结构体的最后一个元素允许是未知大小的数组这就叫做柔性数组成员。struct st_type { int i; int a[]; //int a[];有些编译器不支持这种写法 }3.1柔性数组的特点1.结构中的柔性数组成员前面必须至少⼀个其他成员。2.sizeof返回的这种结构大小不包括柔性数组的内存。3. 包含柔性数组成员的结构⽤malloc()函数进性内存的动态分配并且分配的内存应该大于结构的大小以适应柔性数组的预期大小。3.2柔性数组的使用struct S { int n; int arr[];//柔性数组成员我希望arr开始的时候能存放5个整行后期arr的空间大小可调整 }; int main() { struct S* ps (struct S*)malloc(sizeof(struct S) 5 * sizeof(int));//24 //创建一个结构体指针来接收 if (ps NULL) { perror(use malloc); return 1; } ps-n 100; int i 0; for (i 0; i 5; i) { ps-arr[i] i1; } //扩容 struct S* ptr (struct S*)realloc(ps, sizeof(struct S) 10 * sizeof(int)); if (ptr ! NULL) { //扩容失败 perror(use realloc); } else { //扩容成功 ps ptr; ptr NULL; for (i 5; i 10; i) { ps-arr[i] i 1; } } //释放 free(ps); ps NULL; return 0; }当我们的空间大小需要调整时通过柔性数组就可以做到。3.3柔性数组的优势struct S { int n; int *arr; }; int main() { struct S* ps (struct S*)malloc(sizeof(struct S)); if (ps NULL) { perror(use malloc); return 1; } ps-n 100; int* ptr (int*)malloc(5 * sizeof(int)); if (ptr ! NULL) { ps-arr ptr; } else { perror(use malloc); return 1; } int i 0; for (i 0; i 5; i) { ps-arr[i] i1; } //扩容 struct S* ptr2 (struct S*)realloc(ps-arr, 10 * sizeof(int)); if (ptr2 ! NULL) { //扩容失败 perror(use realloc); } else { //扩容成功 ps-arr ptr2; ptr2 NULL; for (i 5; i 10; i) { ps-arr[i] i 1; } } //释放 free(ps-arr); ps-arr NULL; free(ps); ps NULL; return 0; }这里使用结构体包含指针的方式也能完成但是柔性数组有两个优势。1.方便内存释放如果我们的代码是在一个给别人用的函数中你进行了二次分配内存并且把整个结构体返还给用户用户可以通过free释放结构体但是如果用户不知道结构体内部的成员也要free就会造成内存泄漏。所以我们把结构体的内存和成员变量要的内存一次性分配好然后返回一个结构体指针这样只要做一次free就可以把所有的内存释放。2.有利于提高访问速度连续的内存有益于提⾼访问速度也有益于减少内存碎⽚。
延伸阅读

更多相关文章

2026/10/5 10:27:36

46.大模型应用如何评估不要只看回答听起来像不像

大模型应用如何评估?不要只看“回答听起来像不像” 码海寻道 大模型、智能体与 RAG 工程组件系列第 46 篇 大模型回答流畅、语气自然,不代表它是正确的。企业 AI 应用更应该回答:资料找对了吗?答案有依据吗?权限是否正…

2026/10/5 10:27:36

元宝 LeetCode 227. 基本计算器 II Java实现

LeetCode 227. 基本计算器 II — Java 题解 题目 计算一个字符串表达式的值,表达式包含: 非负整数运算符 “” “-” “*” “/”(无括号)整数除法向零截断 输入: “32*2” → 7 输入: " 3/2 " → 1 输入: &quo…

2026/10/5 10:27:36

Python 中 类变量 vs 全局变量

Python:类变量 vs 全局变量一、定义 & 存放位置全局变量定义在函数、类外部,属于模块对象,保存在模块的 __dict__。g_val 100 # 全局变量,模块级别def test():print(g_val)类变量写在 class 内部、方法外面,属于…

2026/10/5 11:32:40

C#仓库条码管理系统实战:扫码枪接入、库存流水与打印状态机

简介:一份基于 C# 的仓库条码管理系统毕业设计源码,面向计算机相关专业学生及初阶仓库管理开发者。系统采用 Windows Forms 构建界面,围绕条形码扫描实现入库、出库、库存查询与报表生成等核心模块,有助于理解 C# 面向对象编程、窗…

2026/10/5 11:32:40

GESP六级树的遍历:从递归序到非递归,再到还原二叉树

树的遍历,在GESP六级大纲里就像是树这个章节的“敲门砖”。我带过的很多学生,最初都觉得不过就是三种递归写法嘛,背下来就完了,结果到了考场上,一道“已知中序和后序,让你求前序”直接傻眼,或者…

2026/10/5 11:32:40

一文看懂Linux文件类型:从ls -l到inode,彻底搞清七种类型

刚接手一台陌生的 Linux 服务器,或者第一次打开某个开源项目的源码目录时,我几乎都会敲一遍ls -l。这一敲,第一列那一串十个字符,就是整个文件系统的"身份证明"。很多新手盯着drwxr-xr-x、-rw-r--r--发呆,只…

2026/10/5 11:32:40

无摩擦支付:消费双刃剑与实操止损清单

支付越“丝滑”,花钱越“随意”?这份报告把无摩擦支付的消费双刃剑讲透了——附实操止损清单 作为一个和支付产品打了多年交道的人,我太熟悉“无摩擦支付”这个词了。从最初的密码输入,到指纹支付、刷脸支付,再到现在…

2026/10/5 11:32:40

插件加载失败排查:从‘did not activate‘到系统化解决

去年年中我在维护一个内部工具平台的插件模块时,几乎每天都会被类似这样的报错信息折磨:"failed to load plugins web boot: 2 entries did not activate"、"harness failed to load plugins web boot: 1 entry did not activate huayu-y…

2026/10/5 11:27:40

MATLAB/Simulink雷达仿真实战:从信号建模到目标检测

1. 为什么非要用 MATLAB/Simulink 做雷达仿真1.1 雷达仿真到底在仿什么先聊个实际的场景。我去年接手了一个车载毫米波雷达的项目,硬件平台还没到位,算法团队天天喊着要调参,测试场地排期又遥遥无期。当时如果没有一套趁手的仿真工具&#xf…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/4 0:01:02

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/4 1:01:05

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑