欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

malloc,calloc,realloc及动态开辟内存常见错误

程序员文章站 2022-05-12 12:29:37
...

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)原有空间之后没有足够的空间

malloc,calloc,realloc及动态开辟内存常见错误

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申请,释放的空间都是整体的,不能局部释放

  • 对一块动态内存释放多次
  • 动态开辟的空间忘记释放(内存泄漏),切记动态开辟的空间一定要释放,并且要正确的释放