在之前的学习中我们已经知道的内存开辟方式有:
int val = 20; //在栈空间上开辟四个字节
char arr[10] = { 0 }; //在栈空间上开辟10个字节的连续空间
在上面这两种开辟空间的方式有两个特点:
1.空间开辟的大小是固定的.
2.数组在声明的时候,一定要指定数组的长度,它所需要的内存在编译时分配.
在我们的实际应用中,对于所需要的空间需求,往往不仅仅是上面两种情况!也就是说,有时候我们需要的空间大小在程序运行的时候才能知道,那像上面这正数组的编译时开辟空间的方式就不能满足了.这个时候就要用到我们的动态开辟内存了.
这也就是动态内存分配存在的原因.
关于动态能存的几个函数介绍
malloc和free
在C语言中提供了这样一个动态开辟内存的函数:
void* malloc(size_t size);
//开辟size字节的连续空间,并将首地址返回
这个malloc函数向内存申请一块连续可用的空间,并返回指向这块空间的指针.
在使用malloc函数动态开辟内存要要注意:
1.如果内存开辟成功,就返回一个指向开辟好空间的指针,一定要注意malloc函数的返回值是一个指向开辟好空间的指针!
2.如果内开辟失败,就会返回一个NULL指针,这也就意味着,malloc函数的返回值一定要做检查.
3.malloc函数的返回值是void* ,所以malloc函数并不知道开辟空间的类型,所以malloc函数具体在使用的时候由使用者自己来决定.
4.如果malloc函数的参数size为0,那么malloc函数的行为标准是未定义的,具体行为取决于编译器.
来看一个动态内存开辟的例子.
#include <stdio.h>
#include <stdlib.h>
int main(){
int* p = NULL;
p = (int*)malloc(sizeof(int));
*p = 8;
printf("%d\n", *p);
system("pause");
return 0;
}
先创建一个空指针,让这个指针指向动态开辟的4字节空间,然后给其赋值.这样也就完成一个简单动态内存的开辟.但是要注意的是,这样使用malloc函数会造成内存泄漏,malloc函数动态开辟的空间在使用完之后一定要记得释放,这也就用到了free函数.
void* free(void* ptr);
切记,开辟谁,释放谁.
如果参数ptr指向的空间不是动态开辟的,那么free函数的行为是未定义的.
如果参数ptr指向NULL指针,free函数什么都不做.
malloc函数和free函数都声明在stdlib.h头文件中.
所以对上述代码稍作修改
#include <stdio.h>
#include <stdlib.h>
int main(){
int* p = NULL;
p = (int*)malloc(sizeof(int));
*p = 8;
printf("%d\n", *p);
free(p);
p = NULL;
system("pause");
return 0;
}
这样才是malloc函数使用正确方法.
释放掉动态开辟的内存之后我们再次把p置为空,是为了防止p变成野指针(动态开辟的内存释放后,p仍指向这块内存空间,所以释放之后记得将p置为空)
calloc函数
除了malloc函数之外,C语言还提供了一个函数叫calloc,而calloc函数同样也用来动态开辟内存.
void* calloc(size_t num, size_t size);
calloc函数的功能是将num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0.
calloc函数与malloc函数的区别只在于calloc函数会在返回地址之前把申请的空间的每个字节初始化为全0.举例来说:
#include <stdio.h>
#include <stdlib.h>
int main(){
int* p = calloc(10, sizeof(int));
if (p != NULL){
//说明空间开辟成功
//使用动态开辟的空间
}
free(p);
p = NULL;
system("pause");
return 0;
}
所以当我们对申请的内存空间的内容要求初始化的时候,我们就可以很方便的用calloc函数来完成任务.
realloc函数
realloc函数的出现让动态内存管理更加灵活.
有时候我们在动态开辟内存的时候会发现,过去申请的空间太小了,或者有时候我们又会觉得申请的空间过大了,为了合理地动态开辟内存,就一定要对内存的大小做灵活的调整.而realloc函数就可以做到对动态开辟内存大小的调整.
void* realloc(void* ptr, size_t size);
ptr是要调整的内存地址.
size是调整之后的新大小.
注意realloc函数是将当前ptr所指向的空间扩大或缩小到size个字节.
返回值是调整之后内存的起始位置.同样开辟失败返回空.
这个函数在调整内存空间大小的基础上,还会降原来内存中的数据移动到新的空间.
realloc函数在调整内存空间时存在两种情况:
1.原有空间之后有足够大的空间
2.原有空间之后没有足够大的空间.
是情况1的时候,要扩展内存就直接在原有内存之后直接追加空间,原来空间的数据并不会发生变化.
是情况2的时候,原有空间之后没有足够多的空间时,会在堆空间上另找一个合适大小的连续空间来使用.这样的话realloc函数返回的是一个新的内存地址