• 动态内存分配——malloc,calloc,realloc,free


    1.动态内存分配简单描述

    在c语言的编写过程中,为了使程序有更好的移植性,也为了使程序编写起来更加方便,当需要额外虚拟内存时,会使用动态内存分配器(dynamic memory allocator)。
    动态内存分配器维护着进程的虚拟内存区域:堆区

    分配器将视为一组大小不同的块(block)的集合来维护,每个块就是一个连续的虚拟内存片(chunk)

    块的状态有两种,详细介绍如下:
    
    • 1
    虚拟内存片状态描述
    已分配已分配的块显示地保留被应用程序使用。已分配的块保持已分配状态,直到它被释放,这种释放要么是应用程序显示执行的,要么是内存分配器自身隐式执行
    空闲空闲块保持空闲,直到它显式地被应用程序所分配;
    分配器分类如下:
    
    • 1
    分配器分类具体描述
    显示分配器(explicit allocator)要求应用显示地释放任何已分配的块。例如C语言中的malloc
    隐式分配器(implicit allocator)隐式分配器也叫做垃圾收集器,要求分配器检测一个已分配块何时不再被程序所使用,那么就释放这个块,释放过程就叫做垃圾收集

    2.malloc与free函数

    2.1详细介绍

    C标准库提供了一个称为malloc程序包的显式分配器。程序通过调用malloc函数来从堆中分配块。
    malloc不初始化它申请的内存空间。
    calloc函数是一个基于malloc的函数,作用和malloc一样,只不过它将分配的内存初始化为0。
    realloc函数可以改变一个已分配块的大小。
    程序是通过调用free函数来释放已分配的堆块。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    //malloc函数返回指向size字节内存块的指针
    //(在32bit中malloc返回的块的地址总数是8的倍数,在64bit中,是16的倍数)
    void *malloc(size_t size);
    
    //ptr必须指向一个已经已分配块的起始位置,如果不是,那么free的行为就是未定义的。
    void free(*ptr);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    在这里必须要指出free函数的一个缺陷,free函数的返回值是void,如果出现了错误我们也无从得知。
    如果malloc申请内存失败,它将返回NULL
    
    • 1
    • 2

    2.2malloc和free过程图解

    假设:malloc返回的块是8Byte双字边界对齐的。一个方框表示一个字。阴影部分表示已分配块。堆地址从左往右增加。
    
    • 1

    详细过程:
    初始状态:
    在这里插入图片描述

    1. int* p1 =(int*)malloc(sizeof(int) * 4);程序请求4Byte的块。malloc从空闲块的前部切出一个4Byte的块,并返回一个指向这个块的第一个Byte的指针。

    在这里插入图片描述
    2. int* p2 =(int*)malloc(sizeof(int) * 5);程序请求5Byte的块。但是malloc从空闲块的前部切出一个6Byte的块,并返回一个指向这个块的第一个Byte的指针。malloc多分配一个额外的字,是为了保持空闲块是双字边界对齐的。
    在这里插入图片描述
    3. int* p3 =(int*)malloc(sizeof(int) * 6);程序请求6Byte的块。malloc从空闲块的前部切出一个6Byte的块,并返回一个指向这个块的第一个Byte的指针。
    在这里插入图片描述
    4. free(p2);程序释放②中申请的6Byte块。在调用free之后,指针p2仍然指向被释放的内存块,所以应该设置p2=NULL。
    在这里插入图片描述
    5.int* p4 =(int*)malloc(sizeof(int) * 2);程序请求2Byte的块。malloc从空闲块的前部(在前一步中被释放了的内存块)切出一个2Byte的块,并返回一个指向这个块的第一个Byte的指针。
    在这里插入图片描述

    2.3.使用动态内存分配的原因

    在程序编写过程中,为了存放某些固定大小的数据时,我们会使用定长数组等。但是在某些情况下,对于某些数据的大小我们是并不知道的,假如我们还使用定长大小来设置,就会出现如下两种情况:①长度过小导致数据存储不下;②长度过小导致内存浪费。而动态内存分配是根据数据大小分配刚刚好合适的内存空间。

    #include 
    #include 
    
    int main()
    {
        int* array;
        int n = 0;//数据大小
        int i = 0;
        scanf("%d", &n);//输入数据大小
        array = (int*)malloc(sizeof(int) * n);
    
        //循环为每个元素赋值
        for (i = 0; i < n; i++)
        {
            scanf("%d", &array[i]);
        }
        free(array);//释放array内存空间
        array = NULL;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.总结

    要想使用malloc,calloc,realloc,free须先引入stdlib.h头文件

     malloc是向堆区申请一块指定大小的连续内存空间,成功的话返回空间的首地址(保存好malloc开辟的首地址,不要改变其首地址),失败的话返回一个空指针。
     free用来释放内存空间(通过malloc,calloc,realloc获得的动态内存空间),只能释放一次(空指针可以被释放多次)。
     分配成功后如果空间被free之后,任然能够通过指向改变其值,所以在free之后要紧接着置指针为NULL
     calloc与malloc的区别是calloc申请空间后会把空间内容初始化为00000000
     realloc在原有分配空间基础上增加或减少空间。
     堆区:程序运行时可以在堆区动态地请求一定大小的内存,并在用完之后归还给堆区。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    int main()
    {
    	int *p = NULL;
    	int *p1 = NULL;
    	p = (int*)malloc(sizeof(int)*5);//开辟5个连续空间
    	p1 = (int*)malloc(sizeof(int)*5);
    	int *ip = p1;
    	if(NULL == p)//必须有
    	{
    		exit(1);//开辟空间失败,终止当前程序的执行,
    	}
    	for(int i=0;i<5;i++)
    	{
    		p[i]=i;
    	}
    	free(p);//释放p指向的空间,将其还给堆区,这是p还指向该空间。
    	
    	p = NULL;//防止失效指针对内存造成伤害
    	//free和置空NULL这两步必须可少
    	free(ip);//也是一种释放空间的方式
    	p1 = NULL;
    	ip = NULL;
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
     ②动态开辟二维数组(注意释放空间时的顺序)
    
    • 1
    int main()
    {
    	int **s = NULL;//4行5列
    	s = (int**)malloc(sizeof(int*)*4);//s里面存放的时一级指针,所以s为二级指针
    								//4行
    	if(NULL == s)
    	{
    		exit(1);
    	}
    	for(int i = 0;i < 4;i++)
    	{
    		s[i]=(int*)malloc(sizeof(int)*5);//5列
    	}
    	for(int i=0;i<4;i++)
    	{
    		for(int j=0;j<5;j++)
    		{
    			s[i][j]=i+j;
    			printf("%d\t",s[i][j]);
    		}
    		printf("\n");
    	}
    	
    	for(int i=0;i<4;i++)
    	{
    		free(s[i]);		//先释放
    		s[i] = NULL;
    	}
    	free(s);		//释放s指向的空间
    	s  = NULL;
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    realloc表示在原有的基础上面进行追加,扩充到n个某类型空间。
    有三种扩充方案:
    ①后续未分配内存空间足够大,可以分配空间。
    ②后续未分配内存空间不足够大,不能分配空间,这时就会在新的地址分配空间,把原来空间释放掉。
    ③堆内存不足,扩展空间失败,realloc函数返回NULL,这种情况会导致数据丢失,内存泄漏。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    int main()
    {
    	int n = 5,m = 10;
    	int *p = NULL;
    	p=(int*)malloc(sizeof(int)*n);
    	if(NULL == p)
    	{
    		exit(1);
    	}
    	for(int i = 0;i < n;i++)
    	{
    		p[i] = i;
    	}
    	int *s=(int*)realloc(p,sizeof(int)*m);//防止扩充空间失败,出现数据丢失,内存泄漏等情况
    	//扩充后s指向的空间时m*(sizeof(int))==40个字节空间。
    	if(NULL != s)
    	{
    		p = s;
    	}
    	else
    	{
    		printf("追加空间失败\n");
    	}
    	free(p);
    	p = NULL;
    	free(s);
    	s = NULL;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    RNA剪接增强免疫检查点抑制疗效
    flink1.18.0 自定义函数 接收row类型的参数
    基于内存的分布式NoSQL数据库Redis(二)数据结构与通用命令
    Java集合(一)
    软件测试/测试开发丨Web自动化—headless无头浏览器 学习笔记
    HDLBits-Rule110
    Werewolf puzzle Privacy Policy
    震惊 !!!DOM还能这么用,让我们跟随小编一起去看看吧 !
    完整版SpringBoot集成Prometheus配置Grafana监控指标包括响应时间分位数TP90,TP80(图+文)
    蓝桥等考Python组别十级007
  • 原文地址:https://blog.csdn.net/qq_44423388/article/details/127809368