动态内存申请函数:【malloc】【 free】,【calloc 】,【realloc】
为什么存在动态内存分配?
局部变量在栈区。
动态内存开辟在堆区。
全局变量在静态区。
我们已经掌握的内存开辟方式有:
int val = 20; //在栈空间上开辟四个字节
char arr[10] = {0}; //在栈空间上开辟10个字节的连续空间
特点:
1.空间开辟的大小是固定的。
2.数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
有时候我们需要空间的大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。
这个时候我们需要了解动态内存开辟。
动态内存函数的介绍:
1. C语言提供了一个动态内存开辟的函数:malloc
malloc 动态内存申请
void *malloc(size_t size)
int * p = (int *)malloc(10*sizeof(int)); //在堆区开辟10个整型空间这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
-如果开辟成功,则返回一个指向开辟好空间的指针。
-如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
-返回值的类型是void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
-如果参数size 为0,malloc的行为是标准未定义的,取决于编译器。C
2. C语言提供了一个函数:free
void free(void* ptr);
专门用来做动态内存释放和回收。
-如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。
-如果参数ptr是空指针,则函数什么事都不做。
#include<errno.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int *p =(int *)malloc(40);
int i = 0;
if(p == NULL) //判断p是否为空指针
{
printf("%s\n",strerror(errno));
return 0; //若开辟失败,那么在这返回。如果在这没返回,说明p不为NULL,则开辟成功。
}
//开辟成功,开始使用
for(i=0; i<10; i++) //初始化这块空间
{
*(p+i) = i;
}
for(i=0; i<10; i++)
{
printf("%d ",p[i]);
}
//释放空间
free(p);
return 0;
}
注意:
malloc和free 都声明在stdlib.h头文件中。
malloc和free必须成对使用。
3. C语言提供了一个函数:calloc
用来动态内存分配。
void* calloc(size_t num,size_t size)
num 是元素个数
size 是每个元素的长度,单位是字节。
函数功能是为num 个大小为size的元素开辟一块空间,并把空间的每个字节初始化为0.
与函数malloc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0.
举个例子:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p = (int *)calloc(10,sizeof(int)); //开辟了10个整形空间
int i = 0;
if(NULL != p)
{
for(i=0; i<10; i++)
{
*(p+i) = i;
}
for(i=0; i<10; i++)
{
printf("%d ",p[i]);
}
}
free(p);
p = NULL;
return 0;
}
如果是malloc ,在没有初始化的情况下则会输出:随机值。
这就是两者的区别。除此之外函数参数形式上也有所差异(malloc一个参数,calloc两个参数),但也并不难理解。
相比下来,两者之间malloc效率较高,因为malloc没有初始化。
那么主动初始化也是calloc的一个优点,如何选择得看程序员自己的需求。
4. realloc :重新开辟空间
realloc函数的出现,让动态内存管理更加灵活。
有时候我们会发现过去申请的空间太小了,有时候又会觉得大了,那为了合理的使用内存,我们一定会对内存的大小做灵活的调整。那realloc函数就可以做到对动态开辟内存大小的调整。
函数原型:
void* realloc (void *ptr,size_t size);
- ptr (指针指向之前开辟好的空间)是要调整的内存地址。
- size 新开辟空间的大小,单位是字节。
- void* 返回void型的指针,指向重新开辟的内存块。
- 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
- realloc 在调整内存空间是存在两种情况:
情况1:原有空间之后有足够大的空间
此时,要扩展内存就直接原有内存之后追加空间,原来空间的数据不发生变化。 返回原来地址。
情况2:原有空间之后没有足够大空间
此时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。
int main()
{
int *p =(int *)calloc(10,sizeof(int));
int *tmp = NULL; //重新定义一个指针接收新的空间
int i = 0;
if(p == NULL)
{
printf("%s\n",strerror(errno));
return 0;
}
//开辟成功,开始使用
for(i=0; i<10; i++)
{
*(p+i) = i;
}
tmp = (int*)realloc(p,20*sizeof(int));//重新开辟的空间
if(tmp != NULL)
{
p = tmp;
}
for(i=0; i<20; i++)
{
printf("%d ",*(p+i));
}
//释放空间
free(p);
system("pause");
return 0;
}
使用总结:
- realloc失败的时候,返回NULL
- realloc失败的时候,原来的内存不改变,不会释放也不会移动
- 假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址
- 如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。
- 传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的。
- 传递给realloc的指针可以为空,等同于malloc。
上一篇: 葱几月份种最合适?哪里的葱比较知名?
推荐阅读
-
malloc、calloc、realloc函数说明
-
malloc,free,calloc,realloc函数
-
动态内存申请(malloc, calloc, new)之分配虚拟内存空间和物理内存空间
-
malloc、calloc、realloc函数说明
-
动态内存管理及常见错误malloc()、realloc()、calloc()、free()
-
函数malloc,calloc,realloc ,free 的介绍,区别,用法详解
-
C风格的动态内存管理(malloc、calloc、realloc、free)以及总结free崩溃常见的几种情况
-
对动态内存分配函数malloc、calloc、realloc、free的理解
-
动态内存管理-malloc/realloc/calloc/free和new/delete的区别
-
C_动态分配内存:malloc,realloc,calloc,free