动态内存分配(malloc,calloc,realloc)

文章目录

  • 1.为什么使用动态内存分配
  • 2.malloc和free
  • 3.calloc和realloc
  • 4.常见的动态内存分配错误

1.为什么使用动态内存分配

在声明数组时,必须用一个编译时常量指定数组的长度,但是,数组的长度常常在运行时才知道,这是因为它所需要的内存空间取决于输入数据。例如,一个用于计算学生等级和平均分的程序可能需要存储一个班级所有学生的数据,但不同班级的学生数量可能不同。在这种情况下,我们就可以尝试一下动态内存开辟了。

2.malloc和free

malloc 函数原型 :

void* malloc (size_t size); 

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

(1).如果开辟成功,则返回一个指向开辟好空间的指针。

(2).如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。

(3). 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。

(4).如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。

free函数原型 :

void free (void* ptr);

free函数用来释放动态开辟的内存。

(1).free函数释放的是ptr指针所指向的空间,释放完后 ptr 仍然指向被释放的空间,所以释放完空间后记得将 ptr 指针置为 NULL

(2). 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。

(3). 如果参数 ptr 是NULL指针,则函数什么事都不做。

#include 
#include
int main()
{
     
	int* ptr = NULL;
	ptr = (int*)malloc(num * sizeof(int));
	// 判断ptr指针是否为空
	if (ptr != NULL)
	{
     
		int i = 0;
		for (i = 0; i < num; i++)
		{
     
			*(ptr + i) = 0;
		}
	}
	free(ptr);
	ptr = NULL;
	return 0;
}

3.calloc和realloc

calloc 函数原型 :

void* calloc(size_t num_elements,size_t element_size);

calloc 也用于分配内存

函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。

malloc 和 calloc 之间的主要区别是后者在返回指向内存的指针之前把它初始化成0.

#include
#include
int main()
{
     
	int* p = (int*)calloc(10, sizeof(int));
	if (p != NULL)
	{
     
		// 使用空间
	}
	free(p);
	p = NULL;
}

realloc 函数原型 :

void* realloc(void* ptr,size_t new_size);

realloc 函数用于修改一个原先已经分配的内存块的大小,使用这个函数,可以使一块内存扩大或缩小,如果用于扩大一个内存块,存在两种情况

情况1 : 原有空间之后有足够的空间

这块内存原先的内容依然保留,新增加的内存添加到原先内存块的后面,新内存并未以任何方式进行初始化

情况2 : 原有空间之后没有足够大的空间

realloc 函数将分配另一块正确大小的内存,并将原先那块内存的内容复制到新的块上,并释放原来的空间

如果用于缩小一个内存块,该内存块尾部的部分内存便被拿掉,剩余部分内存的原先内容依然保存

最后,如果 realloc 函数的第一个参数为 NULL,那么它的行为就和 malloc 一样,开辟一块 new_size大小的空间

#include
#include
int main()
{
     
	int* p = NULL;
	p = (int*)malloc(100);
	int* ptr = (int*)realloc(p, 1000);
	if (ptr != NULL)
	{
     
		p = ptr;
	}
	// 业务处理
	free(p);
}

4.常见的动态内存分配错误

(1). 对NULL的解引用操作

void test()
{
         
 	int *p = (int *)malloc(INT_MAX/4);  
   	*p = 20;
   //如果p的值是NULL,就会有问题  
    free(p); 
}

(2).对动态开辟空间的越界访问

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); 
}

(3).对非动态开辟的内存进行 free 释放

void test()
{
        
    int a = 10;   
    int *p = &a;   
    free(p);
}

(4).使用 free 释放一块动态开辟内存的一部分

void test() 
{
        
	int *p = (int *)malloc(100);   
 	p++;   
    free(p);
  //p不再指向动态内存的起始位置
}

(5).对同一块动态内存进行多次释放

void test() 
{
         
	int *p = (int *)malloc(100);  
    free(p);   
    free(p);
   //重复释放 
}

(6).动态开辟内存忘记释放

void test()
{
         
 	  int *p = (int *)malloc(100);  
      if(NULL != p)  
     {
         
          *p = 20;   
     } 
}
int main() 
{
         
	test(); 
    while(1); 
}

你可能感兴趣的:(c语言,内存管理,c语言,动态内存分配)