一、动态内存分配的意义
在日常的代码中,我们通常用如下方式开辟空间:
int n = 0;
char ch = 'a';
int arr[10] = { 0 };
但是上述代码有着几种问题,第一:开辟好的内存空间不可变,如果想要改变空间的大小是行不通的。
所以C语言中动态分配就显得尤为重要了。
二、free
函数free是专门用来做动态内存的释放和回收的,原型如下:
无返回类型,参数是指针。
free函数用来释放动态开辟的内存。
对于计算机内存的分布,我们以下图详细解析:
如果指针ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。
如果ptr指向的是空指针,那么free什么都不做。
三、malloc、calloc、realloc
3.1malloc
malloc定义如下:
malloc的返回类型为void*,也就是指针,就是说malloc并没有限制具体的指针类型,我们在使用中可以根据具体的情况将malloc强制转换成所需的类型,例如:(int*)malloc()、(char*)malloc()。
malloc的参数是字节大小,比如想要建立一个20字节整形空间,就可以写为:
(int*)malloc(20)。
malloc申请的空间是一块连续的空间,可以将其想象成数组的存储方式。
在学习malloc时,我们需要掌握以下知识:
(1)如果开辟成功,就会返回一个指向已经开辟好的空间指针。
(2)如果开辟失败,就会返回一个NULL指针,也就是空指针。因此当我们用malloc开辟完一块空间后,需要判别一下指向这个空间的指针是否为空。
(3)返回值类型为void*,所以malloc并不知道所开辟空间的类型,这个需要使用者自己来决定。
(4)如果参数为0,malloc的行为是标准未定义的,取决于编译器。
(5)使用完开辟的空间后,需要及时的进行释放,把指向空间的指针置成NULL。
3.2calloc
C语言中还提供了一个函数叫calloc,也是用于动态内存分配,其原型如下:
calloc与malloc不同的是它的参数需要两个且要用逗号隔开,(sizet-t num,size-t size)的意思是需要开辟num(整数)个size字节大小的空间。与malloc不同的是,calloc开辟的空间会把空间中的数据初始化而malloc则不会,所以从运行速度上来看,malloc会快一些,但是calloc会自动的初始化数据,各有特点。
两个函数对比如下:
使用malloc:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(20);//创建20个字节大小的空间
if (p == NULL)//判断,如果空间申请失败则报错
{
perror("malloc");
return 1;
}
free(p);//用完空间后,及时释放。
p = NULL;//将p置成空指针,避免野指针。
return 0;
}
使用calloc:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)calloc(5, 4);
if (p == NULL)
{
perror("calloc");
return 1;
}
free(p);
p = NULL;
return 0;
}
3.3realloc
realloc函数是为了调整空间大小而生的函数,它能够使空间的调整更加的灵活。
原型如下:
void* realloc (void* ptr, size_t size);
其中,它的返回类型是一个void*,参数(void* ptr)是指向要调整大小空间的指针,参数(size-t size)代表要将空间调整到的空间大小。
realloc函数在调整原内存空间大小的基础上,还会将原来内存空间的数据转移到新的内存空间中来。他调整空间有两种情况:
(1)原有空间之后有足够大的空间。
(2)原有空间之后没有足够大的空间。
对于(1):
要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
对于(2):
原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找⼀个合适大小的连续空间来使用。这样函数返回的是⼀个新的内存地址。