当前位置:网站首页>【C语言进阶】⑨动态内存分配知识总结 超详细
【C语言进阶】⑨动态内存分配知识总结 超详细
2022-07-16 13:43:00 【白杨Cc】

1.为什么存在动态内存分配?
通常:
int a = 20; //在栈空间是哪个开辟四个字节
char arr[10] = {0}; //在栈空间上开辟10个字节的连续空间;
但是,上述开辟的内存的方式有两个缺点:
- 空间开辟的大小是固定的;
- 数组在声明的时候,必须指定数组的长度,和它所需要的内存,以至于在编译时系统分配空间;
- 然而,对于空间的需求,不仅仅是上述的情况;有时候我们需要的空间大小在程序运行的时候才能知道,那数组在定义是给定的固定大小的空间就不能满足需求了,这时候我们就哟尝试动态内存开辟!
请看栈区、堆区、静态区在内存空间中分布

2. 动态内存函数的介绍:
2.1 malloc() and free() 函数
malloc函数原型:
malloc函数向内存申请一块连续可用的空间,并返回指向这块空间的指针;
- 如果开辟成功,则返回一个指向开辟好空间的指针;
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查;
- malloc的返回值类型是void*, 所以malloc函数并不知道开辟空间的类型,具体是什么类型的空间由使用者自己来决定;
- 如果参数size为0,malloc的行为是标准是未定义的,具体取决于编译器;
C语言提供了另一个函数free(),专门是用来做动态内存的释放和回收的;
函数原型:
free()函数用来释放动态开辟的内存;
- 如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的;
- 如果参数ptr是NULL指针,则函数是什么都不做;
用法:
int main()
{
//假设开辟10int类型的空间,总大小为10*szeof(int)
int arr[10]; //栈区上开辟
//动态内存开辟
int* p = (int*)malloc(10*sizeof(int));
//malloc的返回值为void* ,此时我们无法使用,把它换成int*
//使用开辟的空间
//先判断是否开辟成功
if(p == NULL)
{
perror(); //打印错误
return 0;
}
//使用
int i = 0;
for(i = ;i < 10; i++)
{
*(p+i) = i;
}
for(i = 0; i < 10; i++)
{
printf("%d\n",p[i]);
}
//使用完释放空间
free(p);
p = NULL;//手动值为空;
return 0;
}
2.2 calloc()函数
函数原型:
- 函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0;
- 与函数malloc的区别在于:calloc会在返回地址之前把申请空间的每个元素初始化为0;
2.3 realloc()函数
函数原型:
- *memory 是要调整的内存地址;
- size_t size是调整之后的大小;
- 返回值为调整之后的内存起始地址;
- realloc函数会在调整原内存空间大小的基础上,还会将原来的内存中的数据移动到新的空间;
- realloc在调整内存空间的时候存在两个情况:
(1)原有空间之后有足够大的空间,则在原空间后面开辟一段新空间,把整个空间的地址返回;
(2)原有空间之后没有足够大的空间,则realloc函数会拷贝原来的内存空间的值,然后寻找到一块足够大的空闲空间,然后把原来的内存空间存放的数据拷贝在此,然后再往后开辟新空间,然后返回新的内存空间的地址;
- 注:如果realloc函数一直没有找到合适的空间,则会返回空指针;所以我们一般不把realloc函数的返回值直接赋值给指向原来的内存空间的指针,而是创建一个临时指针来存放realloc函数的返回值,然后判断其是否为空,若不为空,再赋值给指向原空间地址的指针;
- realloc函数的出现让动态内存管理更加灵活;
- 有时我们会发现过去申请的空间小了,有时有觉得申请的空间太大了;为了开辟合适的空间,我们一定会对内存的大小做灵活的调整;而realloc函数就可以做到对动态开辟内存大小的调整;
具体使用:
int main()
{
int* p = calloc(110,sizeof(int));
if(*p == NULL)
{
perror(); //打印报错
return 1;
}
//使用动态开辟的地址
int i = 0;
for(i=0;i<10;i++)
{
*(p=i) = i;
}
//此时需要p指向更大的空间时,需要20个int的空间;
int* ptr = realloc(p,20*sizeof(int));
if(ptr != NULL)
{
p = ptr;
}
free(p);
p = NULL;
}
3. 常见的动态内存错误
3.1 对NULL指针解引用操作
错误示范:
int main()
{
int* p = (int*)malloc(100000000000); //动态申请开辟的空间过大,不予开辟
int i = 0;
for(i = 0;i < 10;i++)
{
*(p+i) = i;
}
free(p);
p = NULL;
return 0;
}
解决:对动态开辟的内存指针进行判断,即对malloc函数的返回值进行判断;
3.2对动态开辟空间的越界访问
错误示范:
int main()
{
int* p = (int*)malloc(10*sizeof(int));
if( p == NULL)
{
perror();
return 1;
}
// 越界访问
int i = 0
for(i = 0; i< 40;i++) //只开辟了40个字节空间,而不是开辟了40个元素;
{
*(p+i) = i;
}
free(p);
p =NULL;
return 0;
}
3.3 使用free()释放非动态开辟空间
错误示范:
int main()
{
int arr[10] = {
0}; //在栈区上开辟空间
int* p = arr;
free(p); //错误
p=NULL;
}
3.4 使用free释放动态内存中的一部分
错误示范:
int main()
{
int* p = (int*)malloc(10*sizeof(int));
if( p= NULL )
{
return 1;
}
int i = 0;
for(i = 0;i<5;i++)
{
*p++ = i;
//此时pn不在指向动态开辟的空间起始位置,之后释放只是释放动态开辟空间的一部分;
}
free(p);
p = NULL;
}
3.5 对同一块动态开辟的空间多次释放
错误示范:
int main()
{
int* p =(int*)malloc(100);
free(p);
free(p);
return 0;
}
3.6 动态开辟的空间忘记释放
错误示范:
void test()
{
int* p = (int*)malloc(100);
if( p == NULL)
{
return;
}
}
int main()
{
test();
return 0;
}
p是局部变量,跳出函数后,p的生命周期结束了;而如果没有释放动态开辟的空间,之后在不能找到在test函数动态开辟的空间;久而久之就会造成内存泄露;
- 总结:malloc动态开辟的空间,2种回收方式:
(1)主动free()函数回收
(2)整个程序结束;

边栏推荐
- 七月集训(第16天) —— 队列
- Introduction to C language (7)
- 2022 simulated 100 questions and simulated examination for the main principals of hazardous chemical business units
- 将c语言文件打包成exe可执行程序
- module ‘sklearn. datasets‘ has no attribute ‘fetch_ mldata‘
- 串的概念相关及模式匹配
- Native input['file'] uploads the same file, and onchange problem records will not be triggered repeatedly
- New exploration of Ali mother's display advertising engine: towards the overall optimal allocation of computing power
- 【第33天】或运算 | 的使用 | 连续低位0变1
- Lime of Py: a detailed introduction to the introduction, installation and use of the lime Library
猜你喜欢
![[PaddleSeg源码阅读] 关于PaddleSeg模型返回的都是list这件小事](/img/a4/bc61237e6557762487783f21602973.png)
[PaddleSeg源码阅读] 关于PaddleSeg模型返回的都是list这件小事

请查收,您有一份阿里先锋开源项目清单

阿里达摩院TableQA技术让表格说话
![[I2C of Renesas ra6m4 development board reads bmp180 air pressure and temperature]](/img/88/0777b7f241df2e0169a724343ba482.png)
[I2C of Renesas ra6m4 development board reads bmp180 air pressure and temperature]

与机器对话,阿里达摩院挑战新一代人机对话技术

2022 simulated 100 questions and simulated examination for the main principals of hazardous chemical business units
![LeetCode 剑指Offer II 041滑动窗口的平均值[滑动窗口] HERODING的LeetCode之路](/img/29/ea4b91cc90ca0dd0eea7e6a3d33394.png)
LeetCode 剑指Offer II 041滑动窗口的平均值[滑动窗口] HERODING的LeetCode之路

Image xmage de Huawei: Cherchez toutes les images du monde et voyez enfin Bodhisattva

This article takes you to graph transformers

发论文!AI,机器学习,CV大佬科研项目招生!
随机推荐
If an element is above another element, clicking on the above element will trigger the following element event operation
华为影像XMAGE:求尽世间像,终见菩提心
一次有趣(想打断同事腿)的键盘BUG调试经历
boost 创建文件夹
【Leetcode】232. 用栈实现队列
【第33天】或运算 | 的使用 | 连续低位0变1
(Fibonacci sequence) use the function to output the number of Fibonacc within the specified range (PTA)
【纪中】2022.7.13 3058.火炬手
层出不穷的终端设备适配需求下 未来的响应式Web设计长什么样?
使用plt.savefig()方法保存绘图时出现图片全白或全黑的问题
Pay equal attention to quality and efficiency, test left shift power block storage technology research and development
墨者学院刷题笔记——SQL手工注入漏洞测试(MongoDB数据库)
代码注释的艺术,优秀代码真的不需要注释吗?
【Renesas RA6M4开发板之I2C读取BMP180气压温度】
云原生:Docker 实践经验(四)docker上部署 redis 三主三从集群
(Note)七彩虹30系列显卡——《一键超频》按键
栈的基本操作
2022 hoisting machinery command examination simulation 100 questions simulation examination platform operation
准确率100%,阿里商旅账单系统架构设计实践
树莓派利用OpenCV的图像跟踪、人脸识别等