一、malloc
我们常见的内存开辟空间的方式是在栈空间上开辟空间存放变量
int main()
{
int a=3;//在栈区上开辟了4个字节的内存空间存放变量a
char b[10]={0};//在栈区上开辟了10个字节的连续空间存放数组b的元素
return 0;
}
上述开辟方式有两种特点:
1.空间开辟大小固定
2.数组在申明时,必须指定数组的长度,它所需要的内存在编译时分配
但是有时我们在编译时无法确定我们所需空间的大小,只有在程序运行时才能知道,那数组的开辟方式就行不通了
这时我们可以用到动态内存开辟的函数malloc,我们使用malloc是在堆区上申请一个动态内存空间,malloc函数的返回值是返回这个空间的地址,根据这个地址,我们可以找到这块动态内存空间。
malloc函数:void* malloc(size_t size);
int main()
{
int* a=(int*)malloc(20);//向堆区申请了一块20个字节的连续动态内存空间,返回地址给指针a
return 0;
}
但是使用了malloc函数并不代表一定可以成功开辟你所需要的内存空间
1.如果开辟成功,返回一个指向该空间的指针
2.如果开辟失败,则会返回一个NULL指针
3.如果size为0,malloc的行为标注是未定义的,取决于编译器
4.返回值是void*,编译器并不知道malloc开辟空间的类型,具体在使用是应由使用者自己来决定
所以我们应当在使用完malloc后就要对它返回的指针进行检查,如果为NULL,则说明开辟失败,
使用perror("malloc");语句打印出异常信息
二、free
如果我们使用malloc成功开辟好空间后,但我们却不使用它,会造成内存的浪费,而我们不想浪费它,应该怎么办呢
free函数可以帮助我们将这块动态空间给销毁(还给操作系统),将内存空间释放掉,这样就可以避免空间的浪费
free函数:void free(void* ptr);(malloc和free函数都在stdlib.h头文件中)
注意事项:
1.如果我们free函数的参数指向的空间不是动态开辟的,那么free函数的行为是未定义的
2.ptr为空指针时,free函数什么也不干
3.当我们将动态内存的空间释放掉后,如果我们在释放之前将它赋给了指针,再释放掉这块空间后,这个指针将会变成野指针,所以我们在释放掉空间后,一定要将这个指针置空
free释放后,a置空前可以发现,两次分别启动程序,a的地址是不同的,因为此时a是野指针
三、calloc
calloc函数:void* calloc(size_t num,size_t size);
它的功能是开辟num个大小为size的连续空间,并把空间上每个字节初始化为0
它与malloc函数不同就在于参数多了个num,并且会在函数中就把空间初始化,其余部分和malloc完全一致,返回值也是开辟的空间地址
四、realloc
realloc函数:void* realloc(void* ptr,size_t size);
realloc函数可以将我们动态申请的空间做灵活的调整,有时我们申请的空间过大,我们可以使用realloc函数使其变小,申请过小,我们可以使其变大
1.ptr是要调整的内存空间的地址
2.size是调整后的新大小
3.返回值为新内存空间的地址
4.这个函数在调整原内存空间大小的基础上,还会将原内存上的数据移到新内存空间上
但是使用realloc函数申请更大空间时有两种可能
1.原空间后的内存足够大,可以开辟出我所需增加的内存空间
2.原空间后的内存不够我所需增加的内存空间
当我们遇到情况2时
操作系统会寻找一个能够存放我们扩展以后的内存空间,这样又会出现两种情况
1.找到了一个这样的空间,我们在这个空间起始位置重新开辟一个我们所需的空间大小,然后释放掉原空间的内存,realloc返回重新开辟以后的内存空间地址
2.没找到这样一个地址,也就是开辟空间失败,返回NULL,如果将它赋给ptr,会使我们ptr所指向的原空间找不到了,导致内存泄漏