目录
为什么需要动态开辟内存空间?
1.malloc函数
2.free函数
3.calloc函数
4.realloc
我们已经熟悉了基本的内存开辟方法:
int a = 0;//向内存申请4个字节的空间
char b=0;//向内存申请了1个字节
int arr[10] = {0};//向内存申请了40个字节
我们创建需要的变量,以此向内存申请开辟对应的空间,不过上述的开辟空间方法有一定的局限性:它开辟空间后无法调整,内存大小无法更改,只能维持其有的空间大小。这时,C语言为我们创建了一组动态内存开辟的函数,接下来我们就认识一下吧。
(这里提及的函数的头文件均为
我们可以看到这个函数的返回类型是void*类型,它向内存申请一块连续可用的空间,并返回指向这块空间的指针,切记,此时的指针类型是void*类型,它不指向任何确定的指针,所以我们想要保存这个返回值时需要强制类型转换成自己所需的类型。如果开辟失败,则会返回空指针NULL。
我们开辟了40个字节大小的空间,将它的地址强制类型转换成int*型放入指针变量p中,但malloc会有开辟失败的现象出现,比如:
系统也会自动提示我们内存开辟失败,当失败的时候我们如果继续访问则会失败,所以在使用malloc函数时,务必要进行开辟内存成功与否的检查。
在成功开辟后:
虽然申请了相应的四十个字节的空间,但我们也可以观察到,其分配的最初40个字节空间的值是随机值。然后我们将它们改写成0~9
#include
#include
#include
int main()
{
int*p = (int*)malloc(40);
if (p == NULL)
{
return 1;
}
else
{
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
}
return 0;
}
可以观察到是成功的改变了开辟的该40字节的空间,当我们使用完这个函数时候,由于它是动态内存的开辟,该函数开辟的内存空间均放置在堆区,堆区的特点就是:直到程序运行结束才会返回申请的内存空间,除非我们主动退还空间,不然空间会一直存在。
所以当我们不想用这块儿空间时,就需要我们自己主动释放空间——也就需要我们的free函数。
原型如下:
void* malloc (size_t size);
无返回类型,仅需要,要求返回空间的起始地址即可——该函数专门用来返回malloc开辟的动态内存空间,所以在使用完malloc函数后,我们只需主动返回空间即可,但我们会观察到如下结果出现:
我们会发现p中的值已经成了随机值,但p地址始终存在并未被销毁,也就是说我们还可以找到p这块儿空间。那当我们不小心释放后再次进行对p的访问就会非法访问,为了避免这样的情况出现,我们将p在释放后立即改成NULL即可。
即以此完整的malloc开辟内存空间并正确使用的代码就只需在上面的代码循环后加上:
free(p);
p = NULL;
即可进行一次正确的malloc函数的使用。
C语言还介绍了calloc的动态开辟内存的函数,原型如下:
void* calloc (size_t num, size_t size);
返回类型与malloc相同为void*型,有两个参数,该函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0,这是与malloc函数所不同的,当然,开辟空间失败时也会返回空指针NULL,所以使用时仍需要我们进行判断是否开辟成功,并且也需要使用完开辟的空间后需要进行主动释放空间和制为空指针。
由于malloc和calloc函数使用方法极其类似,我们在此就不多赘述,举例如下:
#include
#include
int main()
{
int *ret = (int*)calloc(10, 4);
if (ret == NULL)
{
return 1;
}
else
{
int i = 0;
for (i = 0; i < 10; i++)
{
*(ret + i) = i;
}
free(ret);
ret = NULL;
}
return 0;
}
我们可以看到开辟的空间会初始化为0,这是与malloc所不同的。
在将如下代码进行完后,我们可以看到开辟的40个字节的空间被赋值成如上结果,最后进行释放空间和空间空指针化即可。所以如果我们对申请的内存空间的内容要求初始化,那么可以很方便的使用calloc函数来完成任务。
(小编提醒一下哦:malloc和calloc函数须要和free函数同时出现使用)
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整,realloc函数的出现也让动态内存管理更加灵活。
函数原型如下:
void* realloc (void* ptr, size_t size);
ptr是要调整的内存地址
size是调整之后新大小
返回值为调整之后的内存起始位置。
这个函数调整原内存空间大小的基础上,还有可能会将原来内存中的数据移动到新的空间
我们需要注意,在使用realloc函数调整内存空间时是有两种情况的:
①原有空间之后有足够大的空间,扩展内存只须在原有内存后直接追加即可
②原有空间之后没有足够的空间,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。
1,比如我们来观察第一种情况,代码如下:
#include
#include
int main()
{
int *ret = (int*)malloc(10, 4);
if (ret == NULL)
{
return 1;
}
else
{
int *tmp = (int*)realloc(ret, 40);
int i = 0;
for (i = 0; i < 10; i++)
{
*(tmp + i) = i;
}
free(tmp);
tmp = NULL;
}
return 0;
}
在执行完malloc函数后,有如下开辟情况:
然后realloc函数执行:
再看地址情况:可以发现,我们只是追加,而tmp的地址与ret一样。
2,我们再来看看情况2:
再来看其地址情况,可以观察到我们是重新开辟的一大段内存空间来存储新的tmp地址
这便是小编认识的三个动态开辟内存空间的函数以及一个释放空间的函数,大概的认识也就如上所述,秉持着读者可以学到的心态来写出这篇文章的,也希望大家多多支持。