乐趣区

关于c:C语言中动态内存分配的本质是什么

摘要: C 语言中比拟重要的就是指针,它能够用来链表操作,谈到链表,很多时候为此分配内存采纳动态分配而不是动态调配。

本文分享自华为云社区《【云驻共创】C 语言中动态内存调配的实质》,作者:G-washington。

C 语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。只管 C 语言提供了许多低级解决的性能,但依然放弃着跨平台的个性,因为 C 语言具备可移植性,可拓展性,可重用性等个性,促使 C 语言依然在编程语言排行榜上占据肯定无利位置。而 C 语言中比拟重要的就是指针,它能够用来链表操作,谈到链表,很多时候为此分配内存采纳动态分配而不是动态调配。

内存调配的概念

通常定义变量(或对象),编译器在编译时都能够依据该变量(或对象)的类型晓得所需内存空间的大小,从而零碎在适当的时候为他们调配确定的存储空间。这种内存调配称为动态存储调配;有些操作对象只在程序运行时能力确定,这样编译时就无奈为他们预约存储空间,只能在程序运行时,零碎依据运行时的要求进行内存调配,这种办法称为动态存储分配。所有动态存储分配都在堆区中进行。

内存不是取之不尽用之不竭,4g、8g、16g 是常见的电脑内存大小,关上工作管理器,能看到不同的利用占据的内存状况。如果一个应用程序占了大部分内存,预计别的利用就资源缓和了,那这个利用可能会被卸载,找个节俭内存的。

内存治理是计算机靠近物理实质的操作,那些程序语言之下的动作,最终都要调动内存来实现。零碎的资源不是有限的,零碎上运行的程序也不是只有这一个,疏忽内存,就会设计出危险的、冗余的代码产品,或者没法更好的交互。

动态内存调配的特点

动态内存是绝对动态内存而言的。所谓动静和动态就是指内存的调配形式。动态内存是指在堆上调配的内存,而动态内存是指在栈上调配的内存。动态内存调配的实质就是,什么时候须要一块内存的时候,再调配这块内存;当不再须要某一块内存的时候,就能够把这块内存开释掉。这种灵便的内存调配形式,正好适宜链表这种数据结构。

传统数组的毛病

数组与动态内存调配相比有以下毛病:

  • 数组的长度必须当时指定,而且只能是常量,不能是变量。
  • 因为数组长度只能是常量,所以它的长度不能在函数运行的过程当中动静地裁减和放大。
  • 对于数组所占内存空间程序员无奈手动编程开释,只能在函数运行完结后由零碎主动开释,所以在一个函数中定义的数组只能在该函数运行期间被其余函数应用。

而“传统数组”的问题,实际上就是动态内存的问题。然而动态内存就不存在这个问题,因为动态内存是由程序员手动编程释的,所以想什么时候开释就什么时候开释。只有程序员不手动编程开释,就算函数运行完结,动态分配的内存空间也不会被开释,其余函数仍可持续应用它。除非是整个程序运行完结,这时零碎为该程序调配的所有内存空间都会被开释。

动态内存的申请与开释

动态内存的申请与开释次要依附两个函数 malloc 和 free。malloc 是一个零碎函数,它是 memory allocate 的缩写。其中 memory 是“内存”的意思,allocate 是“调配”的意思。顾名思义 malloc 函数的性能就是“分配内存”,要调用它必须要蕴含头文件 <stdlib.h>。

malloc() 函数会向堆中申请一片间断的可用内存空间;若申请胜利 ,, 返回指向这片内存空间的指针 , 若失败 , 则会返回 NULL, 所以咱们在用 malloc() 函数开拓动态内存之后, 肯定要判断函数返回值是否为 NULL;返回值的类型为 void 型, malloc() 函数并不知道间断开拓的 size 个字节是存储什么类型数据的 , 所以须要咱们自行决定 , 办法是在 malloc() 前增强制转 , 转化成咱们所需类型 , 如: (int)malloc(sizeof(int)*n).

上面应用 malloc 函数写一个程序,程序的性能是:调用被调函数,将主调函数中动态分配的内存中的数据放大 10 倍。

输入后果是:*p = 100

free 是开释函数,在堆中申请的内存空间不会像在栈中存储的局部变量一样 , 函数调用完会主动开释内存 , 如果咱们不手动开释, 直到程序运行完结才会开释, 这样就可能会造成内存透露, 即堆中这片内存中的数据曾经不再应用, 但它始终占着这片空间, 所以当咱们申请的动态内存不再应用时 , 肯定要及时开释 . 不过须要留神的是,开释并不是指清空内存空间,而是指将该内存空间标记为“可用”状态,使操作系统在分配内存时能够将它重新分配给其余变量应用。

那么,当指针变量被开释后,它所指向的内存空间中的数据会怎么呢?free 的规范行为只是示意这块内存能够被再调配,至于它外面的数据是否被清空并没有强制要求。不同的编译器解决的形式可能不一样。咱们就看一下 VC++6.0 这个编译器是怎么解决的:

可见在 VC++6.0 中,当指针变量被开释后,尽管它依然是指向那个内存空间的,但那个内存空间中的值将会被从新置一个十分小的正数。动态创建的内存如果不必了必须要开释。留神,一个动态内存只能开释一次。如果开释屡次程序就会解体,因为曾经开释了,不能再开释第二次。

综上所述,malloc 和 free 肯定要成对存在,一一对应。有 malloc 就肯定要有 free,有几个 malloc 就要有几个 free,与此同时,每开释一个指向动态内存的指针变量后要立即把它指向 NULL。

注意事项

1) 开释一块内存的一部分是不容许的。动态分配的内存必须整块一起开释。然而,realloc 函数能够放大一块动态分配的内存,无效地开释它尾部的局部内存。

2) 不要拜访曾经被 free 函数开释了的内存。假设对一个指向动态分配的内存的指针进行了复制,而且这个指针的几份拷贝扩散于程序各处。你无奈保障当你应用其中一个指针时它所指向的内存是不是已被另一个指针开释。还要确保程序中所有应用这块内存的中央在这块内存开释之前进行对它的应用。

3) 当动态分配的内存不再须要应用时,应该被开释,这样能够被重新分配应用。分配内存但在应用结束后不开释将引起内存透露 (memory leak)。

点击关注,第一工夫理解华为云陈腐技术~

退出移动版