前言
动态内存分配的引入,对于一般变量和数组的定义,一旦定义完成后,则其在内存中开辟的空间大小就是固定的,例如下面代码:
int a=10;//在栈空间开辟四个字节
int arr[10]={0};//在栈空间开辟4*10个字节
但有时我们需要的空间未知,开辟太小则不足,太大则浪费,因此需要动态内存开辟方式。下面对动态内存函数malloc、calloc、realloc、free的介绍。
一、malloc和free
malloc是C语言提供的动态内存函数,只有一个参数,即需要开辟空间大小,单位自己,主要是在堆区向内存申请一块连续可用的空间;若开辟成功,则返回指向这块空间的指针;若开辟失败,则返回NULL;因此返回值一定要检查,不然会造成对空指针解引用。
free用于内存的释放,不然一直申请会导致堆区内存占用太多,会导致内存泄漏;但释放完之后,指针不会自动置为NULL,需要手动置空,只能释放动态开辟空间。
具体使用如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
//申请40个字节,即10个整数的空间
int* p = (int*)malloc(40);
//p指针的检查和错误信息返回
if (NULL == p)
{
printf("%s\n", strerror(errno));
return 1;
}
for (int i = 0; i < 10; i++)
{
printf("%d\n", *(p + i) = i + 1);
}
free(p);//释放内存
p = NULL;//指针置为空
return 0;
}
若申请成功,在VS2019下打印结果为:
若将申请空间改为4000000000字节,在VS2019下则会报错:
二、calloc
calloc和malloc都是向内存申请空间,但calloc多了一个对内存初始化,将开辟空间全置为0,开辟空间的部分和malloc一样,都需要对返回值进行检查。具体用法如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
//申请40个字节
int* p1 = (int*)calloc(10,sizeof(int));
//p指针的检查和错误信息返回
if (NULL == p1)
{
perror("calloc");//错误信息打印
return 1;
}
for (int i = 0; i < 10; i++)
{
printf("%d\n", *(p1 + i));
}
free(p1);
p1 = NULL;
return 0;
}
此代码输出的为10个0
三、realloc
对于malloc和calloc申请空间不足或过剩时,可使用realloc进行调整;其有两个参数,第一个是需要调整的内存地址,第二个为调整后内存的大小,单位字节,具体使用如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
//申请40个字节
int* p2 = (int*)calloc(5, sizeof(int));
if (NULL == p2)
{
perror("calloc");
return 1;
}
for (int i = 0; i < 5; i++)
{
printf("%d\n", *(p2 + i));
}
int* ptr = (int*)realloc(p2, 10 * sizeof(int));
if (ptr != NULL)
{
p2 = ptr;
}
for (int j = 5; j < 10; j++)
{
printf("%d ", *(p2 + j));
}
free(p2);
p2 = NULL;
return 0;
}
在VS2019下的打印结果为:
前五个0,是calloc申请的初始化好的空间内容,后面五个是内存的地址,是realloc在calloc之前基础上调整的新空间地址,未初始化的
总结
对于malloc、calloc、realloc都是都内存的申请,但是realloc返回值,和之前指针未必一样,需要考虑,原地址后的空间和需要补加的空间大小,若原地址后的空间充足,则返回的指针和需要开辟内存地址相同;否则,则会返回一个新指针。