C语言--动态内存分配

版权声明:本文为博主原创文章,如需转载请注明出处。 https://blog.csdn.net/GOGOmusic/article/details/80293645

1)什么是动态内存分配、静态内存分配。

百度百科中这样定义

静态内存分配:分配内存大小的是固定,比如定义一个数组,数组的大小是我们提前定义好的,一直到程序结束。

动态内存分配:动态内存分配(Dynamic Memory Allocation)就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。

2)为什么要进行动态内存分配?

(1)传统数组(即静态内存分配)有着如下缺点:

int a[5];//正确
int len = 5; int a[len];//错误
  • 数组的长度必须事先确定,而且只能是常整数,不能是变量

  • 传统形式定义的数组,该数组的内存程序员无法手动释放,在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放。

  • 数组的长度一旦定义,其长度就不能更改,数组的长度不能在函数运行的过程中动态的扩充或缩小。
  • A函数定义的数组,在A函数运行期间可以被其它函数使用,但A函数运行完毕之后,A函数中的数组将无法被其他函数使用。也就是说,传统方式定义的数组不能跨函数使用。

​ 而动态内存分配就很好解决了传统数组的这4个缺陷。

(2)其他情况:

​ 如果我们操作的数据对象太大,我们使用的数据大部分时候都默认保存在栈(stack)里面,由系统去管理,会自动给分配内存,但是stack很小,就那么几M,如果你读取一个几十M的文本内容然后保存到一个字符串里,stack肯定会被撑爆了。

​ 另外如果你想准确的控制内存的释放.比如内存比较紧缺,你用完一块内存后就想立马释放掉.如果系统自动去释放的话可能得等到变量生命周期结束时再释放.不会做得到立马释放.

​ 基于上面等一些原因于是出现了堆(heap),这是由用户自己控制的一片内存区,比stack大多了.你可以自由的在里面申请空间释放空间

3)C语言的内存模型–堆、栈、静态区

静态区:保存自动全局变量和static 变量(包括static 全局和局部变量)。静态区的内容在总个程序的生命周期内都存在,由编译器在编译的时候分配。

栈:保存局部变量。栈上的内容只在函数的范围内存在,当函数运行结束,这些内容也会自动被销毁。其特点是效率高,但空间大小有限。

堆:由malloc 系列函数或new 操作符分配的内存。其生命周期由free 或delete 决定。在没有释放之前一直存在,直到程序结束。其特点是使用灵活,空间比较大,但容易出错。

4)如何使用malloc 函数分配内存(动态内存分配)

(1)动态构造一个int型一维数组

(void *)malloc(int size)

malloc 函数的返回值是一个void 类型的指针,参数为int 类型数据,即申请分配的内存大小,单位是byte。内存分配成功之后,malloc 函数返回这块内存的首地址。你需要一个指针来接收这个地址。但是由于函数的返回值是void *类型的,所以必须强制转换成你所接收的类型。也就是说,这块内存将要用来存储什么类型的数据。比如:

char *p = (char *)malloc(100);

在堆上分配了100 个字节内存,返回这块内存的首地址,把地址强制转换成char 类型后赋给char 类型的指针变量p。同时告诉我们这块内存将用来存储char 类型的数据。也就是说你只能通过指针变量p 来操作这块内存。这块内存本身并没有名字,对它的访问是匿名访问。

(2)内存释放

既然有分配,那就必须有释放。不然的话,有限的内存总会用光,而没有释放的内存却在空闲。与malloc 对应的就是free 函数了。free 函数只有一个参数,就是所要释放的内存块的首地址。比如上例:

free(p);

​ free 函数看上去挺狠的,但它到底作了什么呢?其实它就做了一件事:斩断指针变量与这块内存的关系。比如上面的例子,我们可以说malloc 函数分配的内存块是属于p 的,因为我们对这块内存的访问都需要通过p 来进行。free 函数就是把这块内存和p 之间的所有关系斩断。从此p 和那块内存之间再无瓜葛。至于指针变量p 本身保存的地址并没有改变,但是它对这个地址处的那块内存却已经没有所有权了。那块被释放的内存里面保存的值也没有改变,只是再也没有办法使用了。

​ 这就是free 函数的功能。按照上面的分析,如果对p 连续两次以上使用free 函数,肯定会发生错误。因为第一使用free 函数时,p 所属的内存已经被释放,第二次使用时已经无内存可释放了。关于这点,我上课时让学生记住的是:一定要一夫一妻制,不然肯定出错。

​ malloc 两次只free 一次会内存泄漏;malloc 一次free 两次肯定会出错。也就是说,在程序中malloc 的使用次数一定要和free 相等,否则必有错误。这种错误主要发生在循环使用malloc 函数时,往往把malloc 和free 次数弄错了。

(3)内存释放之后

既然使用free 函数之后指针变量p 本身保存的地址并没有改变,那我们就需要重新把p的值变为NULL:

p = NULL;

释放完块内存之后,没有把指针置NULL,这个指针就成为了“野指针”,也有书叫“悬垂指针”。这是很危险的,而且也是经常出错的地方。所以一定要记住一条:free 完之后,一定要给指针置NULL。

5)内存泄漏

内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

所谓内存泄露是因为堆的空间北我们动态分配用完了,这样当我们再去使用动态分配堆的空间的时候就没有足够的空间让我们使用了,这样就需要占有原来的空间,也就是会把其他的空间来储存我们键入的值,这样会导致原来储存的数据被破坏掉,导致了内存的泄露了。

6)总结:什么时候需要进行动态内存分配?

(1)无法预先确定所需要的内存空间大小

(2)要分配的空间太大超过站的大小,一般来说超过2M大小时

(3)内存中的数据需要带回使用,不能放在栈区,智能用动态内存分配

(4)内存较小,想充分利用内存

猜你喜欢

转载自blog.csdn.net/GOGOmusic/article/details/80293645