动态内存管理以及常见错误_zhao111222333444的博客-程序员宅基地

技术标签: malloc  c  内存管理  

存在的意义

我们的内存开辟方式主要是:

int a=0;//开辟4字节的空间
int arr[5]={
    0};//开辟20字节的空间

这样开辟存在着几个问题:
由于变量开辟是在内存中的栈中,空间比较有限。
只能开辟固定的内存空间,不方便后续调整。
在特定的场景下我们并不能获取需要开辟的内存大小。

所以我们有动态开辟空间来解决一些特定情景下的问题。

1.不能确定需要的内存大小,或者是一个变化的内存大小
2.可以开辟较大的空间来操作(动态开辟的内存空间在内存堆上,空间大于变量所在的栈空间)
3.不过虽然很好,但是动态开辟的内存空间需要我们申请的人主动释放,否则会造成严重的内存泄漏。

内存泄漏可以说是一个很致命的问题,尤其是在一些连续运行的地方,如服务器代码。严重的会导致服务器瘫痪。

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些
    存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有
    限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
  2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似
    于链表。

相关函数

1.malloc

C语言提供了一个动态内存开辟的函数:

void* malloc(size_t  size);
//size是指开辟空间的字节数

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

1.开辟成功,则返回一个指向所开辟空间的指针。失败返回NULL;
2.返回值泛型,所以我们可以自己决定。
3.如果参数 size 为0,malloc的行为是标准是未定义的.

我们一般使用malloc的这样用:

int* arr=(int*)malloc(4);

int a[5]={
    0};
char* arr1=(char*)malloc(sizeof(int)*5);
//malloc搭配sizeof更方便
//malloc一般使用是带一个强制类型转换

2.free

C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收的,函数原型如下:

void free(void*arr);

要点:

free函数用来释放动态开辟的内存。
1.如果参数 arr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
2.如果参数 arr 是NULL指针,则函数什么事都不做。

int* arr=(int*)malloc(4);
free(arr);

int a[5]={
    0};
char* arr1=(char*)malloc(sizeof(int)*5);
free(arr1);

3.calloc

他和malloc一样都是开辟堆内存,只不过他会将开辟的空间全部初始化为0;
他和malloc的形参有不同之处,需要注意。

void* calloc (size_t num, size_t size);
//开辟num个大小为size字节的空间

1.函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
2.与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0

int *arr = calloc(10, sizeof(int));
free(arr);
//不用的时候就一定要free掉内存,虽然我们的代码很短,
//在程序结束自动释放,但是大项目就不一定了。

在这里插入图片描述

4.realloc

realloc函数的出现让动态内存管理更加灵活。
他可以改变我们申请的堆空间大小。

void* realloc (void* ptr, size_t size);
//ptr 是要调整的内存地址
//size 调整之后新大小
//返回值为调整之后的内存起始位置。
int *arr = calloc(10, sizeof(int));
int *p=realloc(arr,20);
free(p);
//将calloc出来的40字节变成了20字节

注意:
realloc改变空间大小会出现两种情况:
1.空间起始位置不变(原有空间足够大)
在这里插入图片描述
2.起始位置改变
在这里插入图片描述

常见错误

1.没有判空

INT_MAX是一个宏定义,代表我们可以向操作系统申请内存空间的最大值,正常情况下无法完成,所以说malloc返回了NULL,而我们对于空指针解引用,属于未定义行为。

void test(){
    
int *p = (int *)malloc(INT_MAX);
*p = 10;
free(p);
}

2.越界

越界属于未定义行为。不管是动态开辟还是栈空间的变量,都不可以越界访问。

int* arr=(int *)malloc(sizeof(int)*4);
for(int i=0;i<=4;i++){
    
	*(p+i)=1;
}

3.非动态开辟free

free仅支持动态开辟的内存,否则会报错

int arr[5]={
    0};
free(arr);

4.未完全释放

未完全释放,造成内存泄漏

int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置

5.重复释放

这个重复释放内存空间属于未定义行为。

int *arr = calloc(10, sizeof(int));
int *p=realloc(arr,20);
free(p);
free(arr);

6.没有释放空间

动态开辟的内存空间,不用的时候一定要释放。

int* p=(int*)malloc(12);
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhaocx111222333/article/details/114630735

智能推荐

iOS:极光推送控制器跳转_dienangpiao2051的博客-程序员宅基地

在前面已经做完了极光消息的推送,那么有消息了,如何跳转到需要的控制器呢?其实,主要还是在userInfo这个消息里面做判断来处理,具体如下:下面这两个是远程推送时接收消息的方法,这是应用程序提供的方法,只要成功注册了极光推送,推送消息时,就会调用这两个方法,在这两个方法收到的userInfo消息做判断即可。// Required,For systems with less tha...

GSL计算Bessel贝塞尔函数_Augusdi的博客-程序员宅基地

#define GSL_DLL#include #include #pragma comment(lib, "libgsl_dll_d.lib")#pragma comment(lib, "libgslcblas_dll_d.lib")intmain (void){ double x = 5.0; double y = gsl_sf_bessel_J0 (x); pr

【总结】华为交换机和锐捷交换机的syslog配置_shen12138的博客-程序员宅基地_锐捷交换机配置syslog

锐捷交换机:en #进入特权模式configure terminal #进入配置模式logging userinfo command-log #命令记录logging facility syslog #syslog等级logging server 192.168.10.71 #指定server服务器地址,默认端口514,好像不能修改端口log...

tidb事物介绍_老王笔记的博客-程序员宅基地

脏读、不可重复读、幻读等介绍

php 嵌套函数 闭包 嵌套函数 + 递归调用的 Fatal错误分析_皮子2的博客-程序员宅基地

嵌套函数 定义时 先判断function_exists 防止 递归调用外部函数 导致两次定义内部 函数 导致致命错误看一下PHP手册中是如何说的:<?phpfunction foo(){ function bar() { echo "I don't exist until foo() is called.\n"; }}/* 现在还不能调用bar()函数,因

转换时区_xianhenyuan的博客-程序员宅基地_东八区切换成东七区

印尼是东七区(+7),中国是东八区(西区就是 -7) public static Date dateTimeStampConversionTime(String stamp){ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); formatter.setTime...

随便推点

遗传算法求解TSP问题_Deer dolphin的博客-程序员宅基地_遗传算法求解tsp问题

遗传算法求解TSP问题(讨论不同参数的组合对结果的影响)### 1.遗传算法基本原理及求解TSP问题流程1.1基本思路TSP问题是一个经典的组合优化问题,让种群中每个个体代表一条路径,经过选择,染色体交配,变异,不断迭代达得到一个路径较短结果。1.2群体的初始化采用生成随机数的方法,初始化规模为N的群体,对染色体的每一维变量进行初始化赋值;随机生成N个城市序列,每个个体是一条城市序列随机...

使用JavaScript获取和设置嵌套对象_cuozhun3051的博客-程序员宅基地

使用JavaScript获取和设置嵌套对象 早在MooTools和jQuery之类JavaScript框架占据统治地位时,我们所有人都编写了一些教程,这些教程更多地针对给定的框架,而不是原始JavaScript。 悲伤但真实。 这些天来,我避免使用面向框架的文章,因为Node.js接管了世界,而JavaScript工具包也应运而生。 我写过但仍然喜欢的一个非常有用的文章是使用MooTo...

梯度下降(Gradient Descent),一句代码,一个式子_GarfieldEr007的博客-程序员宅基地

一直以来,总是觉得国外的PhD们的教育以及课程的安排很好很强大,虽然是说很累作业多工作量大,但是功率大了,效果好点儿,浪费的时间也少,年轻人哪有怕苦怕累的。比比身边好多每天睡超过12小时的研究生们,不知道是谁更幸福一点儿。我也经常拿我所在的大学的研究生博士跟自己所了解的美国那边的phd比比,说实话感觉总是有点硬性的差距在里面。我所处在大学的研究生教育,就拿安排的课程来说,觉得真是有用的不多

mongodb学习之:文档操作_dianjie9145的博客-程序员宅基地

在上一章中有讲到文档的插入操作是用insert的方法。如果该集合不在该数据库中,mongodb会自动创建该集合并插入文档用find的方法可以查找所有的集合数据&gt;db.maple.find(){"_id":ObjectId("5a35d6278ef76f6d57aae92c"),"name":"zhf"也可以将数据定义为一个变量:document=...

Php导出Excel文件乱码的解决_皓月明的博客-程序员宅基地

Php导出Excel文件时有两个主要的过程:1、定义文件名2、填充Excel数据这两个过程中可能会出现一些乱码问题,下面我来说一下解决办法:解决文件名的乱码:乱码原因:客户使用的中文版Windows系统平台,而Windows平台的文件名编码为gb2312(gbk),而我们网页编码为了跟进现存潮流一般都采用utf-8(国际化)编码,这时当我们:head