首先从思维导图大概了解一下malloc,realloc和calloc函数
1.malloc函数
函数功能:malloc能从堆区申请空间给与我们使用,同时返回那片空间所处的首位置的地址。从图我们也能看到malloc返回的为void*类型的指针。
我们从下面的代码来了解这个函数
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
int main()
{
//申请空间
int* a = (int*)malloc(20);//这个代码malloc函数会从堆区上申请20个字节的空间,并将这个空间的首地址返回,
//但是这个返回去的地址是void*类型的所以要进行强制类型转换
//使用空间
if (a == NULL)
{
printf("error:%s", strerror(errno));
return 0;//当空间创建失败的时候也就不用再继续执行代码了所以提前返回
}
for (int i = 0; i < 5; i++)
{
a[i] = i + 1;
}
for (int i = 0; i < 5; i++)
{
printf("%d", a[i]);
}
//释放空间(当我们使用空间完毕后要将其释放)
//使用free
free(a);//这个代码的意思就是将从a开始的在堆区上的空间返回给系统,
//但是此时的a里的地址指向任然是那片空间,此时的a就成了野指针
a = NULL;//将a里的值修改成空
return 0;
}
代码运行结果:
当我将上面的malloc创建的空间改为2000000000000000000运行结果就会
如果不进行判断那么就可能出现问题,所以判断空间是否开辟成功是不可或缺。
总结:使用malloc函数创建空间的时候要注意返回值要强制类型转换,否则无法使用还有每一个内存
创建函数创建空间后,使用完空间后要释放空间,同时将指向那片空间的指针赋值为空指针。
2.calloc
函数功能:和malloc函数一样但是会将创建的空间里面的值全部初始化为0
这是上面的那个代码运行后a,以及里面所储存的值地址可以看到地址指向的空间里面所储存的值为-842150451,这就是编译器在创建空间时默认给的值,可见malloc函数并不会将所创建的空间里面的值给初始化,但是calloc就会
同样是创建20个字节大小的空间:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
int main()
{
//申请空间
int* a = (int*)calloc(5,sizeof(int));//这个代码calloc函数会从堆区上申请20个字节的空间,并将这个空间的首地址返回,
//前面的5就代表申请的空间为5个元素大小,后面的表达式代表一个元素的大小。
//但是这个返回去的地址是void*类型的所以要进行强制类型转换
//使用空间
if (a == NULL)
{
printf("error:%s", strerror(errno));
return 0;
}
for (int i = 0; i < 5; i++)
{
a[i] = i + 1;
}
for (int i = 0; i < 5; i++)
{
printf("%d", a[i]);
}
//释放空间(当我们使用空间完毕后要将其释放)
//使用free
free(a);//这个代码的意思就是将从a开始的在堆区上的空间返回给系统,
//但是此时的a里的地址指向任然是那片空间,此时的a就成了野指针
a = NULL;//将a里的值修改成空
return 0;
}
cealloc运行可见cealloc创建的空间会被初始化为0
3.realloc
函数功能:修改ptr指向的空间大小,修改为size字节的大小。
代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
int main()
{
//申请空间
int* a = (int*)malloc(20);//这个代码calloc函数会从堆区上申请20个字节的空间,并将这个空间的首地址返回,
//前面的5就代表申请的空间为5个元素大小,后面的表达式代表一个元素的大小。
//但是这个返回去的地址是void*类型的所以要进行强制类型转换
//使用空间
if (a == NULL)
{
printf("error:%s", strerror(errno));
return 0;
}
for (int i = 0; i < 5; i++)
{
a[i] = i + 1;
}
int* pc=(int*)realloc(a, 40);//这个代码的功能就是修改a所指向的那片空间的大小,并且返回首空间的地址
//
if (pc == NULL)
{
printf("error:%s", strerror(errno));
return 0;
}
a = pc;
for (int i = 5; i < 10; i++)
{
a[i] = i + 1;
}
for (int i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
//释放空间(当我们使用空间完毕后要将其释放)
//使用free
free(a);//这个代码的意思就是将从a开始的在堆区上的空间返回给系统,
//但是此时的a里的地址指向任然是那片空间,此时的a就成了野指针
a = NULL;//将a里的值修改成空
return 0;
}
运行结果:
接下来我们思考以下问题:
1.realloc创建的新空间是否被初始化过呢?
从图我们能知道很明显并没有。
2.既然realloc会扩大空间那么如果扩大后的空间会占用其它函数创建的空间,那么此时realloc函数又会返回那里的地址呢?
验证代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
int main()
{
//申请空间
int* a = (int*)malloc(20);//这个代码calloc函数会从堆区上申请20个字节的空间,并将这个空间的首地址返回,
//前面的5就代表申请的空间为5个元素大小,后面的表达式代表一个元素的大小。
//但是这个返回去的地址是void*类型的所以要进行强制类型转换
//使用空间
if (a == NULL)
{
printf("error:%s", strerror(errno));
return 0;
}
for (int i = 0; i < 5; i++)
{
a[i] = i + 1;
}
int* pc=(int*)realloc(a, 4000000000);//这个代码的功能就是修改a所指向的那片空间的大小,并且返回首空间的地址
//
if (pc == NULL)
{
printf("error:%s", strerror(errno));
return 0;
}
a = pc;
for (int i = 5; i < 10; i++)
{
a[i] = i + 1;
}
for (int i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
//释放空间(当我们使用空间完毕后要将其释放)
//使用free
free(a);//这个代码的意思就是将从a开始的在堆区上的空间返回给系统,
//但是此时的a里的地址指向任然是那片空间,此时的a就成了野指针
a = NULL;//将a里的值修改成空
return 0;
}
下面的图片是我调式得来的,此时运行到了刚刚扩大新空间
从这我们就能知道realloc确实扩大了空间不过不是从原空间开始扩展的,而是换了一个有这么多大小并且不会占用其它函数空间的空间,并且返回了那个新空间的首地址
但是如果我们执行下面的代码又会发现不同情况
验证代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
int main()
{
//申请空间
int* a = (int*)malloc(20);//这个代码calloc函数会从堆区上申请20个字节的空间,并将这个空间的首地址返回,
//前面的5就代表申请的空间为5个元素大小,后面的表达式代表一个元素的大小。
//但是这个返回去的地址是void*类型的所以要进行强制类型转换
//使用空间
if (a == NULL)
{
printf("error:%s", strerror(errno));
return 0;
}
for (int i = 0; i < 5; i++)
{
a[i] = i + 1;
}
int* pc=(int*)realloc(a, 40);//这个代码的功能就是修改a所指向的那片空间的大小,并且返回首空间的地址
//
if (pc == NULL)
{
printf("error:%s", strerror(errno));
return 0;
}
a = pc;
for (int i = 5; i < 10; i++)
{
a[i] = i + 1;
}
for (int i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
//释放空间(当我们使用空间完毕后要将其释放)
//使用free
free(a);//这个代码的意思就是将从a开始的在堆区上的空间返回给系统,
//但是此时的a里的地址指向任然是那片空间,此时的a就成了野指针
a = NULL;//将a里的值修改成空
return 0;
}
可见此时realloc返回的值还是原来空间的地址,因为此时这片空间可以扩大到我们要求的大小,并且不会占据其它函数空间,所以返回了原来的地址。
由此我们也就能知道:
realloc函数当原空间能扩大到我们所要求的大小并且不会占据其它函数的空间,那么它就会返回原来空间的地址,但是当原空间不能扩大到我们所要求的大小或是会占据其它函数的空间之时,reallco就会释放原空间并去找到一个新空间能满足我们的要求并且不会占据其它函数空间,之后返回这片新空间的首地址。
这篇文章就写到这里了,希望能对阅读的你有所帮助,如果发现任何错误,请严厉指出,我一定虚心接收并且改正。