前言

大家好,今天给大家带来的是动态内存分配相关的知识,今天会讲到三个函数,malloc,calloc,realloc.这三个函数。

介绍

给大家简单介绍介绍一下动态内存的作用,先带大家了解一下数组, 在学动态内存函数前,其实我们用的一直都是数组,用数组去开辟内存,比如 image.png 这样的话,我就创建了一个可以存放十个整形元素的数组,也就是40个字节,一个整形是4个字节,十个就是40,但是如果我们并没有在数组里面存放十个元素,就存放了五个,那么我们剩下的5个元素的位置是不是就浪费了,毕竟编译器可不聪明,不会看出来你不要后面的字节,他会一直给你保留的,那这样是不是就造成了内存浪费了,或者说,我想要存15个元素,那么我十个元素的大小是不是就不够用,那就肯定会造成越界的错误,所以我们接下来讲到的动态内存函数,就可以解决这些问题。

正文

malloc

给大家看一下malloc函数的参数类型,返回类型。 image.png 1.返回的指针指向该开辟的内存块的开头 2.因为新分配的内存并没有初始化,所以可能 image.png image.png 存放的都是一些随机值,后面会讲到给内存初始化的函数。 3.如果当我们开辟的是0个字节的话,在不同的编译器中,我们的返回值可能是空指针因为开辟失败,也可能不是空指针,就像在vs里面 image.pngimage.png 大家可以看见vs的返回值是不空指针,没有进入if的判断。 4.还有就是,如果我们的内存开辟失败,那么他就会返回空指针,如果我们再给开辟失败内存的空指针赋值,那就会出现不可预料的错误,如下图 image.png 我们给int*p赋值了一个大到编译器无法处理的内存,就会报错,最后就如上图。 所以想要避免这种事我们就需要加个判断 image.png 这样就可以避免返回的是空指针再去给空指针赋值了,这样就避免了错误的赋值。 5.free,这个函数不算重要,但是却不能没有他,他的作用就是释放之前开辟过的内存,如果内存不进行释放的话,就会造成内存泄漏,在咱们这些小程序员中还不太明显,但是如果到了腾讯,阿里那种大公司,一个程序几百万行代码,如果有一个地方造成了内存泄漏,那如果想要修复就是特别特别困难,虽然return 0之后会结束程序,并且释放全部内存,但是有的程序可能会运行一个星期,一个月,期间如果不去自己释放内存,那真的就会造成分严重的内存泄露,到最后内存不够用之后死机,那真的哭都没地方哭。

calloc

image.png 1.这个是calloc函数,给大家讲解一下他的参数和返回类型, image.png 举个例子,如果我想要4个int类型大小的元素,就可以用image.png 这样就相当于开辟了4*4=16个字节的空间,其实就是元素个数×元素大小。 2.大家可以看到,前面说了,calloc函数返回的是初始化的内存块,于是我们可以看见,image.png 如果我们不进行赋值,直接打印的话就是,image.png 0,对因为我们的内存进行了初始化,这就是calloc和malloc函数的主要区别。 当然,在malloc函数中介绍到的内存泄露,内存开辟不成功这些问题在calloc函数中也会进行判断,所以大家可以看到我每次开辟完内存都会进行if判断是不是空指针。

realloc

带大家了解一下realloc函数 image.png、 这四个框框里面的后面介绍,先带大家了解一下realloc函数的返回类型以及函数参数类型 image.png 下面讲解框框里面的知识 1.更改所指向的内存块的大小,这个比较好理解,大家可以看下图, image.png 大家可以看到上面的calloc函数开辟的是4*4=16个字节,但是经过下面的realloc函数,我的p是一个具有了100个字节空间的大小,就这样我们,就将100个字节的空间赋给了p,但是大家可能会问,你这个下面的判断什么意思啊,为什么不能直接传给p呢,为什么需要经过判断一下呢,接下来就讲到了第二个框框里面的知识。 2.为什么他会说可能会将内存块移动到新的位置呢,这个就涉及到了这个p指针后面的空间是否可以容纳后续开辟的空间,我给大家画出来, image.png 大家看这种情况,我们的已经开辟的内存后面还有一部分空余的空间,允许我们去扩容,那些蓝色的格子是这个内存中被占用的地方,这种情况的下,我们是可以直接给p进行内存增容的,但是还有一种情况 image.png 这个空间的话,大家可以看见,该内存后面的内存空间已经不支持再去扩容了,如果非要扩容的话,那么就可能会把后面内存里面的信息包含在我的内存里面,这样就会出现问题,所以我们就可以换个方法, image.png 我们可以去开辟一个新的内存块,在这个内存块先将上面内存里面的值复印过来,再加上后面扩容的内存也不会去盖住后面的内存,就可以避免上面的问题,还有个小知识点就是,我们的p指针因为里面的内存里面的值都复制给了ptr所以p指针内部的空间就被这个函数释放了,归还给的电脑,这就很方便,但是我们不知道什么时候会开辟失败,所以我们每次扩充内存的时候都进行创建一个新的指针,那么就可以完全的避免了这个问题, 3.意思是,将原有的内容保留到新开辟内存的低地址处,即使是开辟了一个新空间也如此,但是如果开辟的内存大于之前地址的话,后面新增容的内容就会是不确定的值,也就是随机值。 4.

如果这是一个空指针,则函数的行为类似于,分配一个新的字节块并返回指向其开头的指针。

image.png 什么意思呢? 其实意思很简单,就是我们如果是给一个空指针进行内存扩充, 大家看到,p是空指针如果要给p进行内存扩充的话,也是没问题的,大概意思就相当于是malloc函数的意思,增容的内容也都是随机值,并且返回值是指向其开头的指针。 5.还有以个很重要的点就是,我们的realloc其实可以做到缩小自己内存大小的作用,如下图: image.png 我们给intp 20个字节的空间,分别对(p+i)进行了赋值,得到了图片右面的内存, 但是由于我后面又给p的内存进行了realloc缩短了内存,这样我们的打印就变成了image.png因为我们的内存变成了8个字节,只够打印两个整形,所以后面的值也就因为内存没有覆盖或者涉及到变成了随机值,也可以通俗一点说(缩小内存是对原内存里面的内容进行了截断)。 好了朋友们,这次的讲解知识我们先认识一下动态内存管理,到后面我还会进行几个经典题型的讲解,会在后续发出,大家可以三连走一走,谢谢大家!!!