malloc,calloc,realloc及动态开辟内存常见错误
1.为什么存在动态内存管理?
我们已经掌握的内存开辟方式有:
int val = 20;//在栈空间上开辟四个字节
char arr[10] = {0}; //在栈空间上开辟10个字节的连续空间
但是这些开辟空间的方式开辟的空间大小是固定的,数组在声明的时候,也是必须指定大小。他们所需要的内存在编译时分配
而有些时候我们需要的空间大小在程序运行的时候才能知道,所以就要有一种动态内存分配的方式
动态开辟的内存都在堆上
2.如何动态的分配内存?
c语言提供了一个动态内存开辟的方式:
- malloc:向内存动态的申请一块空间
- 函数原型: void * malloc (size_t size);
- 函数说明:
1)这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针
2)如果开辟成功,则返回一个指向开辟好空间的指针
3)如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
4)返回值类型是void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候由使用者自己来决定。
5)如果参数size为0,malloc的行为是标准为定义的,取决于编译器
c语言提供了另一个函数free,专门用来做动态内存的释放和回收的
- free:用来释放动态开辟的内存
- 函数原型: void free(void* prt);
- 函数说明:
1)如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的
2)如果参数ptr是NULL指针,则函数什么事都不做
malloc和free都声明在头文件#include<stdlib.h>中
int main()
{
int *ptr = NULL;
ptr = (int*)malloc(10*sizeof(int));
if (ptr != NULL)//一定要检查是否为空
{
printf("haha\n");
}
free(ptr);//一定要记得释放
ptr = NULL;
return 0;
}
//使用时要判断ptr是否为空,动态申请的内存一定要使用free()释放,并且置空,否则可能引起内存泄漏的问题
- calloc:用来动态开辟内存,不同于malloc的是,它会进行初始化
- 函数原型:void* calloc(size_t num,size_t size);
- 函数说明:
1)calloc函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节都初始化为0
2)与函数malloc的区别在于calloc会在返回地址之前把申请的所有空间的每个字节都初始化为0
int main()
{
int *ptr = NULL;
ptr = (int*)calloc(10, sizeof(int));
if (NULL != ptr)
{
printf("haha\n");
}
free(ptr);
ptr = NULL;
return 0;
}
- realloc:可以对动态开辟的内存大小进行调整,realloc函数的出现使动态内存管理更加灵活,有时候我们申请的空间太大,或者太小了,就可以使用realloc对其进行调整
- 函数原型:void* realloc(void* ptr,size_t size);
- 函数说明:
1)ptr是要调整的内存地址
2)size是调整之后的新大小
3)返回值为调整直观的内存起始位置
4)这个函数在调整原内存空间大小的基础上,还会将原来内存中的数据移动带新的空间
- realloc函数在调整内存空间存的时候在俩种情况
1)原有空间之后有足够大的空间
2)原有空间之后没有足够的空间
int main()
{
int *ptr = (int*)malloc(10 * sizeof(int));
int * newptr = NULL;
newptr = (int*)realloc(ptr, 100);
if (NULL != newptr)
{
printf("haha");
}
free(newptr);
return 0;
}
3.常见的动态内存错误
- 对NULL指针进行解引用操作
void test() { int * ptr = (int*)malloc(10*sizeof(int)); *ptr = 20; free(ptr); }
//如果开辟内存失败,ptr=NULL,对空指针进行解引用会出错,所以使用前要先判断ptr是否为NULL
- 对动态开辟空间的越界访问
void test()
{
int i = 0;
int *p = (int*)malloc(10 * sizeof(int));
if (NULL == p)
{
exit(EXIT_FAILURE);
}
for (i = 0; i <= 10; i++)
{
*(p + i) = i;//当i=10的时候越界访问
}
free(p);
}
- 对非动态开辟内存的释放,栈上申请的空间,不需要用free释放
- 使用free释放一块动态开辟内存的一部分
void test() { int *p = (int*)malloc(100); p++; free(p); }
//p++后不在指向动态内存的起始位置,malloc申请,释放的空间都是整体的,不能局部释放
- 对一块动态内存释放多次
- 动态开辟的空间忘记释放(内存泄漏),切记动态开辟的空间一定要释放,并且要正确的释放
推荐阅读
-
malloc,calloc,realloc及动态开辟内存常见错误
-
动态内存管理及常见错误malloc()、realloc()、calloc()、free()
-
C风格的动态内存管理(malloc、calloc、realloc、free)以及总结free崩溃常见的几种情况
-
对动态内存分配函数malloc、calloc、realloc、free的理解
-
动态内存管理-malloc/realloc/calloc/free和new/delete的区别
-
C_动态分配内存:malloc,realloc,calloc,free
-
【c语言】动态内存管理(malloc、free、calloc、realloc)
-
C语言动态内存管理:malloc、realloc、calloc以及free函数
-
C语言动态内存分配——malloc,calloc,realloc,free
-
C语言中动态内存管理方式(malloc、calloc、realloc的区别)