当前位置: 代码迷 >> 综合 >> 动态分配内存与销毁(malloc、free、malloc、realloc)
  详细解决方案

动态分配内存与销毁(malloc、free、malloc、realloc)

热度:35   发布时间:2023-12-12 23:59:12.0

malloc函数

在数组分配空间的时候,如果十个例子九个是10个元素以内,但是有一个却为100+的,如果为了这一个数组而创建一个很大的数组,那么显然是不合理的,所以我们还要有其他的方式来创建一个动态数组。

比如vla数组(变长数组),就是一个不错的选择,今天我们还有另外一个更好的选择,malloc函数。
vla数组参见之前的博客:变长数组——VLA

和vla数组一样,动态数组不是将一个小数组拓展成一个大数组,而是在创建的时候才确定数组的大小。

函数原型:

void *malloc(size_t);//size_t是一种类型,是sizeof运算符的返回值

size_t到底是什么,这个不是重点,只要知道参数是要分配的空间大小即可。
(一般来说是unsigned int用typedof重命名来的)
重点是前面的返回值,void指针。

void指针是什么
void无类型,要是创建一个这样的变量,系统不知道该分配多少空间,就会报错;如果是指针,那么就可以指向任意一个空间,但是呢在解引用void指针时,问题又来了,系统又不知道指向的空间多大了。。。所以还是报错

强转void指针
为了进行解引用,我们就需要使用类型强转,和其他类型强转一样,加一个括号就行了。

int x = 5;
printf("%d",(float)x);void *p = &x;
printf("%d",*(int *)p);

这样第二个输出就是5了。

所以我们也可以用相同的方式来使用malloc函数

int *p = (int *)malloc(sizeof(int)*10);

这样就给p分配了10个int型的空间,就相当于一个10空间大小的int数组,和vla数组相比也是各有千秋。
例:
在这里插入图片描述
下面的方式是不行的

int *p;
*p = 5;

我们将*p赋值为5,看起来确实找不到什么问题,但是细想,p的值应为一个地址,但是在这里我们却没有为其分配地址,而malloc比较暴力,不是用现成的地址而是直接分配一个空间给他。
这个例子可能让你对malloc函数的作用有更深刻的理解吧

用完malloc函数的问题

这时,我们分配了一个空间给这个指针,如果是对生存期有了解的读者一定知道在块或者函数结束了,内部创建的变量就会自动将内存归还(在创建变量的时候系统分配了内存给这些变量),但是自己亲自分配的空间就让系统很难办了,什么时候才将空间释放呢?C很相信程序员,所以就交给程序员来处理了。
这时就是free函数登场的时候了,无返回值,唯一的参数是指针。
例:

int *p = (int *)malloc(sizeof(int));
……
free(p);

因为参数是一个地址,所以我们不需要一定是同一个变量名来malloc和free

int *p = (int *)malloc(sizeof(int));
int *temp = p;
……
free(temp);

这在销毁链表的时候还是有用处的,毕竟直接销就断链了。

另外只能free一次,对一个空间free多次也是很危险的行为。

不用free释放空间,也行,下面就讲一下危害。
首选就是虽然指向这部分内存的指针已经在文件结束的时候被释放了,但是这片区域还是有东西的,程序就不能动,所以可用的空间就会变少,最后造成内存泄漏。

(其实也不是很吓人,毕竟当时写链表不知道忘了多少次了。。。另外现在的系统也考虑到了问题,所以有一些会自动帮你将泄露的空间处理)

calloc函数

也是分配空间的,既然要重新给出一个,所以这个也是有自己的优点的。
calloc函数,返回void类型,参数1为每一部分的大小,参数2部分数,同时将块中所有位置值置为0在这里插入图片描述
(咳咳,那个全局变量是意外,和本例子无关,上面的截图也是)
也需要free(),这个函数就像是专门为用指针创建数组准备的。

int m=5, n=4;
int a[m][n];
int (*p)[m];//数组指针
p = (int (*)[m] malloc(n*m*sizeof(int));

realloc函数

如果创建的空间不合适了,那么可能我们需要进行调整,那么就可以使用realloc函数。

void *realloc(void *ptr, size_t size) (第一个参数是之前malloc或者是calloc的指针,另一个是大小。
如果是空指针(这里指的不是指向NULL,而是没有分配空间的指针)也可以进行分配。

注意一下,虽然第一个参数是void类型指针,但是因为我们需要强转malloc函数的返回值,那么是不是还需要改回void指针?其实是不需要的

int main()
{
    int *p = (int *)calloc(10,sizeof(int));realloc(p,20);for(int i=0;i<20;i++)printf("%d ",p[i]);//直接当成数组名return 0;
}

在这里插入图片描述
可以看到calloc函数是有置零的,但是realloc函数没有。

多维数组和空间分配

这时,变长数组就要更胜一筹了,举例:

int m = 5, n = 4;
int vla[m][n];//变长数组int (*p)[n];
p = (int (*)[n])malloc(m*n*sizeof(int));//malloc分配空间,也需要一部分的变长数组

malloc函数麻烦的一批,很容易出错。

首先是一个变长数组的数组指针,然后对着这个空间分配,并强转成p的类型。