C/C++动态内存开辟详解(含常见错误以及经典面试题)
动态内存开辟
- 1.四个重要的内存函数
- 1.1 malloc和free
- 1.2 calloc
- 1.3 realloc
- 2.常见错误
- 2.1 对NULL指针进行解引用操作
- 2.2 对动态开辟内存的越界访问
- 2.3 使用free释放非动态开辟的空间
- 2.4 使用free释放了动态开辟内存的一部分
- 2.5 对同一块动态内存开辟的空间多次释放
- 2.6 动态开辟的空间忘记释放,造成内存泄漏
- 3.经典面试题
- 第一题
- 第二题
- 第三题
- 第四题
1.四个重要的内存函数
1.1 malloc和free
C语言提供了一个动态内存开辟的函数:
void malloc (size_t size);*
这个函数向申请一块连续可用的空间,并返回指向这块空间的指针。
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要检查。
- 返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
- 如果参数size为0,malloc的行为的标准是未定义的,取决于编译器。
C语言还提供了另外一个函数free,专门是用来做动态内存的释放和回收的,函数原型如下:
void free(void ptr);
free函数用来释放动态开辟的内存。
- 如果参数ptr指向的空间不是 动态开辟(如数组名) 的,那free函数的行为是未定义的。
- 如果参数ptr是NULL指针,则函数什么事也不做。
malloc和free都声明在stdlib.h头文件中。
1.2 calloc
C语言还提供了一个函数叫calloc,calloc函数也用来动态内存开辟。原型如下:
void calloc(size_t num,size_t size);*
- 函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节都初始化为0.
- 与函数malloc的区别只在于calloc会返回地址之前把申请的空间的每个字节初始化为全0.
1.3 realloc
- realloc函数的出现让动态内存管理更加灵活。
- 有时我们会发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的使用内存,我们一定会对内存的大小做灵活的调整。那realloc函数就可以做到对动态开辟内存大小的调整。
函数原型如下:
void realloc(void ptr,size_t size);**
- ptr是要调整的内存地址
- size调整之后的新大小
- 返回值为调整之后的内存起始位置
- 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移到新的空间 。
- realloc在调整内存空间时候存在两种情况:
情况1: 原有空间之后有足够大的空间
情况2: 原有空间之后没有足够大的空间
2.常见错误
2.1 对NULL指针进行解引用操作
#include<stdio.h>
int main()
{int *p = (int*)malloc(100000000000);//开辟内存过大,可能会开辟失败,返回空指针int i = 0;for(i = 0;i<10;i++){*(p+i) = i;}
}
解决方法:在申请空间后对p进行判断。
if(p == NULL)
return 1;
2.2 对动态开辟内存的越界访问
#include<stdio.h>
int main()
{int *p = (int*)malloc(10*sizeof(int));//申请10个int空间大小if(p==NULL)return 1;int i=0;// 越界访问for(i=0;i<40;i++){*(p+i)=i;}
}
2.3 使用free释放非动态开辟的空间
int main()
{int arr[10]={0}//存于栈区int *p=arr;free(p);//使用free释放了数组申请的空间p=NULL;return 0;
}
2.4 使用free释放了动态开辟内存的一部分
int main()
{int* p=(int*)malloc(10*sizeof(int));if(p==NUL)return 1;int i=0;for(i=0;i<5;i++){*p++ = i;}free(p);p=NULL;return 0;
}
解读:p指向开辟内存的首地址,而在循环赋值中,p只对其中5个int大小进行了赋值,而后就对该空间释放。除此之外p受++运算符不断向后移动,使得p的初始位置改变,这很容易导致内存泄漏。
2.5 对同一块动态内存开辟的空间多次释放
int main()
{int* p=(int*)malloc(100);//使用//释放free(p);p=NULL;//释放free(p);return 0;
}
2.6 动态开辟的空间忘记释放,造成内存泄漏
解决方法:在该指向这块空间的指针的生命周期结束前使用free函数释放。
3.经典面试题
第一题
void GetMemory(char* p)
{p = (char*)malloc(100);
}
void Test(void)
{char* str=NULL;GetMemory(str);strcpy(str,"hello,liren");printf(str);
}
请问运行Test函数会有什么样的结果?
答案:程序奔溃!
解读:str传给GetMemory函数的时候是值传递(因为并不是使用str所指地址的值而是改变str本身的值),所以GetMemory函数的形参p是str的一份临时拷贝。在GetMemory函数内部动态申请空间的地址,存放在p中,不会影响外边str,所以当GetMemory函数返回之后,str仍然是NULL,所以strcpy会失败。(当GetMemory函数返回之后,形参p销毁,使得动态开辟的100个字节存在内存泄露)
第二题
char* getmemory(void)
{char p[]="hello,liren";return p;
}
void test(void)
{char* str=NULL;str=getmemory();printf(str);
}
int main()
{test();return 0;
}
这种题称为返回栈空间地址的问题
答案:一堆乱码!
解答:getmemory函数内部创建数组是在栈区上创建的,出了函数,p数组的空间就还给了操作系统,返回的地址是没有实际的意义的,如果通过返回的地址,去访问内存就是非法访问内存的。
第三题
void getmemory(char** p,int num)
{*p = (char*)malloc(num);
}
void test(void)
{char* str=NULL;getmemory(&str,100);strcpy(str,"liren");printf(str);
}
int main()
{test();return 0;
}
答案:程序奔溃!
解答:应在test函数里面使用free函数释放str,并将其设为空指针。
第四题
void test(void)
{char* str=(char*)malloc(100);strcpy(str,"liren");free(str);if(str!=NULL){strcpy(str,"love tongtong");printf(str);}
}
int main()
{test();return 0;
}
答案:程序奔溃!
解答:test函数中提前free了一次,造成下面的非法访问内存。(注:使用free后并不会将指针置空,必须要手动置空)
—————————————————————————————————
到此为止,应该对动态内存开辟有相当的了解了吧,那接下来我会更新如何运用动态内存开辟制作一个通讯录,持续更新!(还将设计文件操作的知识)
C/C++动态内存开辟详解(含常见错误以及经典面试题)相关推荐
- C语言动态内存开辟详解(malloc,calloc,realloc,free,柔型数组)
目录 一.概述 二.相关库函数的使用 1.malloc 2.calloc malloc vs. calloc 异同 3.free的使用 4.realloc 三.易错点 四.C\C++程序的内存开辟规则 ...
- SpringMVC接受JSON参数详解及常见错误总结我改
SpringMVC接受JSON参数详解及常见错误总结 最近一段时间不想使用Session了,想感受一下Token这样比较安全,稳健的方式,顺便写一个统一的接口给浏览器还有APP.所以把一个练手项目的前 ...
- C语言动态内存分配详解
文章目录 前言 一.为什么存在动态内存分配 1.已掌握的内存开辟方式 2.上述开辟空间方式的特点 3.为什么存在动态内存分配 二.动态内存函数的介绍 1.malloc 2.free 3.calloc ...
- 【C语言】动态内存分配详解
目录 一.为什么有动态内存分配 二.动态内存分配函数 (1)malloc()函数 (2)calloc()函数 (3)realloc()函数 三.常见的动态内存错误 1.越界访问 2.内存泄漏 3.对N ...
- 【C++】动态内存分配详解(new/new[]和delete/delete[])
原文链接:https://blog.csdn.net/qq_40416052/article/details/82493916 代码还是原文看着方便,在此不调整格式了 一.为什么需要动态内存分配? 在 ...
- Spark 内存管理详解(下):内存管理
本文转自:Spark内存管理详解(下)--内存管理 本文最初由IBM developerWorks中国网站发表,其链接为Apache Spark内存管理详解 在这里,正文内容分为上下两篇来阐述,这是下 ...
- jvm之java内存区域详解篇guide哥yyds
jvm 一.java内存区域详解 1.运行时数据区域 线程私有的: 虚拟机栈 本地方法栈 程序计数器 线程共享的: 堆 方法区 直接内存(非程序运行时数据区的一部分) 1.1什么是程序计数器 程序计数 ...
- Linux进程地址空间与进程内存布局详解,内核空间与用户空间
Linux进程地址空间与进程内存布局详解 程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码. 初始化过的数据(Data):在程序运行初已经对变量进行初始化的数据. 未初始化过的数据( ...
- 【C语言】动态内存开辟
目录 一.动态内存开辟的原因 二.动态内存开辟函数 1.malloc函数 2.free函数 3.calloc 4.realloc 总结 三.C/C++内存开辟 四.柔性数组 1.柔性数组定义 2.柔性 ...
最新文章
- 2019年,我终于知道86版西游记到底好在哪里了
- html瀑布式原理,纯css3+html瀑布流效果
- 信息北航身份认证_信息北航丨北航第一服务平台,你值得关注!
- ubuntu中clion更换cmake版本以及文本背景颜色
- 在生产中配置和使用AWS EKS
- hadoop伪分布式配置
- cobbler介绍与部署
- fcpx视觉特效插件包 - FxFactory for Mac 支持M1芯片
- mysql 填充结果,mysql为测试数据库填充大量数据
- Idea安装Eslint插件详解 提示:Plugin NativeScript was not installed解决
- tomcat多实例的端口设置
- java编写进行货币兑换_货币汇率java assignment
- JS 平方 开方 笔记
- delphi android 打印机,delphi中如何检测打印机状态?(在线等) ( 积分: 100 )
- wpf给模板控件添加事件一
- 炮兵阵地图文详解NOI2001/POJ1185(状态压缩)
- React---hooks的使用
- 应对焦虑的时候,需要学会一次只解决一个问题
- jenkins--将构建结果上传到构建页面(Archive the artifacts)
- 数据结构与算法 第八天常见排序+冒泡排序+快速排序+文件IO+大数据排序+文件合并
热门文章
- Delaunay三角网之逐点插入法
- 理解网络交换机的原理
- 乐山计算机学校军训,心有多大,舞台就有多大!乐山这名中职学生考上双一流211重点大学...
- 论文笔记:Mind the Gap An Experimental Evaluation of Imputation ofMissing Values Techniques in TimeSeries
- “pip-script.py”is not present的问题
- AUI tab实现页签滑动切换且下拉刷新(下拉固定title栏及tab栏)
- C#接入steam内购
- 工作多年想转行,有哪些正确的方法及技巧呢
- 训练好的深度学习模型原来这样部署的!(干货满满,收藏慢慢看)
- oracle数据库中的系统自带表情_教你如何让数据库支持emoji表情符存储