C语言的动态内存管理的深入了解
一、动态内存分配
- (1)用malloc类的函数分配内存;
- (2)用这些内存支持应用程序;
- (3)用free函数释放内存。
内存的简答来说的三大操作:分配----使用----释放
内存管理指的是:分配— ----释放
我们编写的程序代码:使用
程序本质上就是处理数据,数据信息需要存放在内存里,就是用二极管表示的开断表示二进制数,进一步用二进制数表示万物:如音乐、文字、视频、图片、等等各种资源。
分配–释放:为了更好的利用和回收内存资源,最大程度的发挥计算资源,统一操作系统来调度
动态内存分配其实就要谈到自动内存分配
自动分配:内存其实就是我们在编程文件里定义的变量实际在运行时映射的内存,这部分变量的内存都是由系统自动管理(分配-释放)。函数体(或者语句块)内的变量都是分布在函数 帧 里面,运行时就会把这个帧插入到函数运行栈里,内存这些都由系统分拨,运行完就出栈,内存也被操作系统回收,一致到主函数出栈,程序退出。
动态分配:就是我们自己手动申请操作系统给我们程序分配的内存,内存区域主要在于 堆 上,这部分资源是我们手动申请和回收的。分配到的资源是我们来操作、存放数据的地方。
实际上我们定义的变量最后也会被翻译为地址,都是通过寻址来操作变量的值(可以去看看汇编语言)
#include <stdio.h> #include <stdlib.h> int main(void) { int*pi=(int*)malloc(sizeof(int)); *pi=5; printf("*pi:%d\n",*pi); free(pi); return 0; }
注意点
int *pi=(int)malloc((4));
- 然而,依赖于系统所用的内存模型,整数的长度可能会发生变化。可移植的方法是使用sizeof操作符,这样不管程序在哪里运行都会返回正确的长度。
- 使用(int)malloc(number * (sizeof(int)));*
二、动态内存分配函数
有几个内存分配函数可以用来管理动态内存,虽然具体可用的函数取决于系统,但大部分系统的stdlib.h头文件中都有如下函数:
malloc()
realloc()
calloc()
函数 | 描述 |
---|---|
malloc | 从堆上分配内存 |
realloc | 在之前分配的内存块的基础上,将内存重新分配为更大或者更小的部分 |
calloc | 从堆上分配内存并清零 |
1、malloc()
malloc函数从堆上分配一块内存,所分配的字节数由该函数唯一的参数指定,返回值是void指针,如果内存不足,就会返回NULL。此函数不会清空或者修改内存。
声明:void* malloc(size_t);
- (1)从堆上分配内存;
- (2)内存不会被修改或是清空;
- (3)返回首字节的地址。
实例用法:int* pi=(int*)malloc(sizeof(int));
因为当malloc无法分配内存时会返回NULL,在使用它返回的指针之前先检查NULL是不错的做法,如下所示:
int*pi=(int*)malloc(sizeof(int)); if(pi!=NULL) { //指针没有问题 }else { //无效的指针 }
- (4)静态、全局指针和malloc
初始化静态或全局变量时不能调用函数。下面的代码声明一个静态变量,并试图用malloc来初始化:
*static int pi = malloc(sizeof(int));
这样会产生一个编译时错误消息,全局变量也一样。
对于静态变量,可以通过在后面用一个单独的语句给变量分配内存来避免这个问题。但是全局变量不能用单独的赋值语句,因为全局变量是在函数和可执行代码外部声明的,赋值语句这类代码必须出现在函数中:
static int *pi;
pi = malloc(sizeof(int));
2、realloc()
声明:void *realloc(void *ptr,size t size);
realloc函数返回指向内存块的指针。该函数接受两个参数,第一个参数是指向原内存块的指针,第二个是请求的大小。重新分配的块大小和第一个参数引用的块大小不同。返回值是指向重新分配的内存的指针。
第一个参数 | 第二个参数 | 行为 |
---|---|---|
空 | 无 | 同malloc |
非空 | 0 | 原内存块被释放 |
非空 | 比原内存块小 | 利用当前的块分配更小的块 |
非空 | 比原内存块大 | 要么在当前位置要么在其他位置分配更大的块 |
堆管理器可以重用原始的内存块,且不会修改其内容。不过程序继续使用的内存超过了所请求的8字节。也就是说,我们没有修改字符串以便它能装进8字节的内存块中。在本例中,我们本应该调整字符串的长度以使它能装进重新分配的8字节。实现这一点最简单的办法是将NUL赋给地址507。实际使用的内存超出分配的内存不是个好做法,应该避免。
3、calloc()
calloc函数在申请内存时会清空内存【清空内存的意思是将其内容置为二进制0】
声明: void *calloc(size_t numElements,size_t elementSize);
calloc函数会根据numElements和elementSize两个参数的乘积来分配内存,并返回一个指向内存的第一个字节的指针。如果不能分配内存,则会返回NULL。此函数最初用来辅助分配数组内存。
如果numElements或elementSize为0,那么calloc可能返回空指针。如果calloc无法分配内存就会返回空指针,而且全局变量errno会设置为ENOMEM(内存不足),这是POSIX错误码,有的系统上可能没有。
三、用free函数释放内存
有了动态内存分配,程序员可以将不再使用的内存返还给系统,这样可以释放内存
留作他用。通常用free函数实现这一点,该函数的原型如下:
声明: void free(void *ptr);
指针参数应该指向由malloc类函数分配的内存的地址,这块内存会被返还给堆。尽管指针仍然指向这块区域,但是我们应该将它看成指向垃圾数据。稍后可能重新分配这块区域,并将其装进不同的数据。
要点
- 释放含义:指的是释放堆上的申请内存,其实就是告诉堆管理器,这个资源我不用了,可以回收了
- 但本地还是保留了之前申请内存的地址,这个地址我们应该避免去使用,也就是置这个指针为NULL
- 不能再去接引已释放资源指针的值
- 不能重复多次释放指针指向的内存(free)
四、迷途指针
如果内存已经释放,而指针还在引用原始内存,这样的指针就称为迷途指针。迷途指针没有指向有效对象,有时候也称为过早释放。
迷途指针带来的问题:
- 如果访问内存,则行为不可预期;
- 如果内存不可访问,则是段错误;
- 潜在的安全隐患。
造成的原因:
- 访问已释放的内存;
- 返回的指针指向的是上次函数调用中的自动变量;
//第一种情况 int*pi = (int*)malloc(sizeof(int)); printf("*pi:%d\n",*pi); free(pi); *pi = 10; //第二种情况 int*p1 = (int*)malloc(sizeof(int)); *p1 = 5; int* p2; p2 = p1; free(p1); *p2 = 10;//迷途指针 //第三种情况 /* 大部分编译器都把块语句当做一个栈帧。tmp变量分配在栈帧上,之后在块语句退出时会出栈。 pi指针现在指向一块最终可能被其他活跃记录(比如foo函数)覆盖的内存区域。 图2-13说明的就是这种情形。 */ int *pi; int tmp = 5; pi = &tmp; //这里pi变成了迷途指针 foo();
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注猪先飞的更多内容!
原文出处:https://blog.csdn.net/qq_43680827/article/details/122779971
相关文章
- 这篇文章主要为大家详细介绍了C语言实现放烟花的程序,有音乐播放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-23
- 本篇文章主要介绍C语言中char的知识,并附有代码实例,以便大家在学习的时候更好的理解,有需要的可以看一下...2020-04-25
- ps动态环绕动画效果是现在很多人都非常喜欢的,大多数人还不知道ps动态环绕动画效果怎么制作下面文章就给大家介绍下ps怎么制作科技感十足的动态环绕动画效果,一起来看看...2017-07-06
- 这篇文章主要介绍了详解如何将c语言文件打包成exe可执行程序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-25
- 这篇文章主要介绍了vue 实现动态路由的方法,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-06
- 这篇文章主要介绍了浅谈redis key值内存消耗以及性能影响,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-07
- 这篇文章主要介绍了详解分析MySQL8.0的内存消耗,帮助大家更好的理解和学习使用MySQL,感兴趣的朋友可以了解下...2021-03-23
- 今天我们来给大家介绍下在Vue开发中我们经常会碰到的一种需求场景,本文主要介绍了Vue动态查询规则生成组件,需要的朋友们下面随着小编来一起学习学习吧...2021-05-27
- free函数是释放之前某一次malloc函数申请的空间,而且只是释放空间,并不改变指针的值。下面我们就来详细探讨下...2020-04-25
- 这篇文章主要介绍了C语言中计算正弦的相关函数总结,包括正弦和双曲线正弦以及反正弦的函数,需要的朋友可以参考下...2020-04-25
详解C语言中的rename()函数和remove()函数的使用方法
这篇文章主要介绍了详解C语言中的rename()函数和remove()函数的使用方法,是C语言入门学习中的基础知识,需要的朋友可以参考下...2020-04-25- 这篇文章介绍了c#动态调用Webservice的两种方法实例,有需要的朋友可以参考一下...2020-06-25
- 本文详细讲解了SQLServer中执行动态SQL的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2022-05-19
- 这篇文章主要介绍了C语言中求和、计算平均值、方差和标准差的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-10
- 想在网页中动态地显示当前系统的时间,找了好多,不过都是一些停在那里不动的。。。不过皇天不负有心人,终于让我找到了...2020-06-25
- 这篇文章主要介绍了解决使用OpenCV中的imread()内存报错问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-16
- 下面小编就为大家带来一篇jQuery为动态生成的select元素添加事件的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-09-01
- 本篇文章主要讲解C语言 基本语法,这里提供简单的示例和代码来详细讲解C语言的基本语法,开始学习C语言的朋友可以看一下,希望能够给你带来帮助...2021-09-18
- 护卫神·主机管理系统该版本支持在Windows Server 200320082012,含32位和64位,直接开设配置WEB站、FTP站,以及SQL Server和MySQL,是您开设和管理虚拟主机的绝好帮手。但是对于新用户可能在使用上有一些困难,因此请仔细阅读如下说明文档...2016-01-27
- 最近由于项目的需要,需要动态的添加和删除table中的tr,感觉用JS可以实现,但是在网上找了一下,单纯的自己写JS,感觉太麻烦,而且也不好维护。于是想到了最近学的jQuery。这篇文章给大家用实例介绍了jQuery动态添加与删除tr行的方法,有需要的朋友们可以参考借鉴。...2016-10-20