malloc、calloc和realloc是动态内存开辟的函数,在了解他们之前先想一下为什么要动态内存开辟?
我们以前开辟内存时是通过下面这种方式:
int val = 10; //在栈上开辟四个字节
char arr[10] = {0};//在栈上开辟10个字节的连续空间
这种方式是在栈上开辟内存,有以下特点:
1.开辟的空间是固定的;
2.数组在声明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
可是有时我们需要的空间大小在程序运行时才能知道,所以在编译时开辟空间的方式就不能满足。所以这时候只能试试动态内存开辟。
C语言提供了三个动态内存开辟的函数:malloc、calloc和realloc
malloc
函数原型:
void* malloc(size_t size);
用来向内存申请一块连续可用的空间,空间开辟成功则返回指向这块空间的指针,失败返回NULL指针,所以必须对返回值做检查,判断内存是否开辟成功。
特点:开辟的空间没有初始化,如果这块内存空间原来没有被使用过,则其中的每一位可能都是0;反之,如果这部分内存曾经被分配过,那么就有可能出错,所以使用这块空间前先将其初始化。
calloc
函数原型:
void* calloc(size_t num,size_t size);
函数的功能是为num个大小为size的元素开辟一块空间,并把每个空间初始化为0.
如果是为字符类型或整数类型的元素分配内存,那么这些元素将被初始化为0,如果为指针类型的元素分配内存,那么这些元素通常会被初始化为空指针,如果是浮点型元素,则这些元素会被初始化为浮点型的0。
realloc
函数原型:
void* realloc(void* ptr,size_t size);
该函数可以调整动态开辟的内存大小。
ptr是调整后的内存地址,size是调整后的新大小,返回值为调整后的内存的起始地址。
realloc在调整内存空间时存在两种情况:
1.原有空间之后有足够大的空间:
扩展内存直接在原有内存之后直接追加,原有空间数据不发生变化。
2.原来空间之后没有足够大的空间:
扩展方式:在堆空间另找一个合适大小的连续空间,然后将原来数据拷贝到新空间,这时函数返回一个新的内存地址。
注意:所有动态开辟的内存都要手动释放,用free函数,否则会内存泄漏。
验证malloc和calloc:
#include <stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = (int*)malloc(10 * sizeof(int));
if (ptr != NULL)
{
int i = 0;
for (; i < 10; i++)
{
*(ptr + i) = 0;
}
}
free(ptr);
ptr = NULL;
return 0;
}
使用malloc结果:
调用该函数后分配了4*10个字节的大小,但是没有进行初始化。
使用循环将这些空间初始化为0.
调用calloc函数呢?
#include <stdio.h>
#include<stdlib.h>
int main()
{
int* ptr = NULL;
ptr = calloc(10, sizeof(int));
if (ptr != NULL)
{
}
free(ptr);
ptr = NULL;
return 0;
}
结果:
从上图可以看见,calloc函数自动将其分配的空间初始化为0了。
三者区别:
1.三者的声明都在 stdlib.h头文件中。
2.calloc可以初始化所分配的内存空间,而其他两个不能。
3.realloc可以对动态开辟的内存空间进行扩大或缩小,无论是扩大还是缩小,原有的内存中的内容将保持不变,当然,对于缩小,则被缩小的那一部分的内容将会丢失,realloc并不保持调整后的内存空间和原来的内存空间保持同一内存地址,realloc返回的指针很可能指向新的地址。