• 28 动态内存分配


    1 动态内存分配的意义

    • C语言中的一切操作都是基于内存

    • 变量数组都是内存的别名

      • 内存分配由编译器在编译期间决定
      • 定义数组的时候必须指定数组长度
      • 数组长度是在编译期就必须确定
    • 需求:程序运行的过程中,可能需要使用一些额外的内存空间

    2 malloc 和 free

    • mallocfree 用于执行动态分配内存和释放

    • malloc 所分配的是一块连续的内存

    • malloc字节为单位,并且不带任何的类型信息

    • free 用于将动态内存归还系统

      void* malloc(size_t size);
      void free(void* pointer);
      
    • 注意

      • mallocfree库函数,而不是系统调用
      • malloc 实际分配的内存可能会比请求的多
      • 不能依赖于不同平台下的 malloc 行为——为了移植性
      • 当请求的动态内存无法满足时,malloc 返回 NULL
      • free 的参数为 NULL 时,函数直接返回
    • 问题1:malloc(0); 将会返回什么?

      • Demo

        #include <stdio.h>
        #include <malloc.h>
        
        int main()
        {
            int* p  = (int*)malloc(0);
        
            printf("p = %p
        ",p);
            
            free(p);
        
            return 0;
        }
        
      • 运行结果 => malloc(0)是合法的,但申请的内存长度为0

        p = 0x895a008
        
    • 问题2:如果不断地执行 malloc(0); 但是不进行内存释放,会产生内存泄漏么?

      • 会:malloc 实际分配的内存可能会比请求的多malloc(0); 可能得到的内存是 4 个字节大小
    • 实例:内存泄漏检测模块

      • Demo

        #include <stdio.h>
        #include "mleak.h"
        
        void f()
        {
            MALLOC(100);  //自定义的malloc函数,这里没有进行内存释放
        }
        
        int main()
        {
            int* p = (int*)MALLOC(3 * sizeof(int));
            
            f();
            
            p[0] = 1;
            p[1] = 2;
            p[2] = 3;
            
            FREE(p);  //自定义的free函数
            
            PRINT_LEAK_INFO();  //打印当前内存泄漏的信息
            
            return 0;
        }
        
        
        //mleak.h
        #ifndef _MLEAK_H_
        #define _MLEAK_H_
        
        #include <malloc.h>
        
        #define MALLOC(n) mallocEx(n, __FILE__, __LINE__)
        #define FREE(p) freeEx(p)
        
        void* mallocEx(size_t n, const char* file, const line);
        void freeEx(void* p);
        void PRINT_LEAK_INFO();
        
        #endif
        
        //mleak.c
        #include "mleak.h"
        
        #define SIZE 256
        
        /* 动态内存申请参数结构体 */
        typedef struct
        {
            void* pointer;
            int size;
            const char* file;
            int line;
        } MItem;
        
        static MItem g_record[SIZE]; /* 记录动态内存申请的操作 */
        
        void* mallocEx(size_t n, const char* file, const line) 
        {
            void* ret = malloc(n); /* 动态内存申请 */
            
            if( ret != NULL )
            {
                int i = 0;
                
                /* 遍历全局数组,记录此次操作 */
                for(i=0; i<SIZE; i++)
                {
                    /* 查找位置 */
                    if( g_record[i].pointer == NULL )
                    {
                        g_record[i].pointer = ret;
                        g_record[i].size = n;
                        g_record[i].file = file;
                        g_record[i].line = line;
                        break;
                    }
                }
            }
            
            return ret;
        }
        
        void freeEx(void* p)
        {
            if( p != NULL )
            {
                int i = 0;
                
                /* 遍历全局数组,释放内存空间,并清除操作记录 */
                for(i=0; i<SIZE; i++)
                {
                    if( g_record[i].pointer == p )
                    {
                        g_record[i].pointer = NULL;
                        g_record[i].size = 0;
                        g_record[i].file = NULL;
                        g_record[i].line = 0;
                        
                        free(p);
                        
                        break;
                    }
                }
            }
        }
        
        void PRINT_LEAK_INFO()
        {
            int i = 0;
            
            printf("Potential Memory Leak Info:
        ");
            
            /* 遍历全局数组,打印未释放的空间记录 */
            for(i=0; i<SIZE; i++)
            {
                if( g_record[i].pointer != NULL )
                {
                    printf("Address: %p, size:%d, Location: %s:%d
        ", g_record[i].pointer, g_record[i].size, g_record[i].file, g_record[i].line);
                }
            }
        }
        
      • 运行

        
        

    3 calloc 和 realloc

    • malloc 的同胞兄弟

      void* calloc(size_t num,size_t size);
      void* realloc(void* pointer,size_t new_size);
      
    • calloc参数代表所返回内存的类型信息

    • calloc 会将返回的内存初始化为0

    • realloc 用于修改一个原先已经分配的内存块大小

      • 在使用 realloc 之后应该使用其返回值
      • pointer 的**第一个参数为 NULL 时,等价于 malloc **
    • 对比

      • malloc 单纯地从系统中申请固定字节大小的内存
      • calloc 能以类型大小为单位申请内存并初始化为0
      • realloc 用于重置内存大小,如果内存重置为一个更大的内存空间,扩充的部分为随机值
    • 示例:callocrealloc 的使用

      • Demo

        #include <stdio.h>
        #include <malloc.h>
        
        #define SIZE 5
        
        int main()
        {
            int i = 0;
            int* pI = (int*)malloc(SIZE * sizeof(int));
            short* pS = (short*)calloc(SIZE, sizeof(short));
            
            for(i=0; i<SIZE; i++)
            {
                printf("pI[%d] = %d, pS[%d] = %d
        ", i, pI[i], i, pS[i]);
            }
            
            printf("Before: pI = %p
        ", pI);
            
            pI = (int*)realloc(pI, 2 * SIZE * sizeof(int));
            
            printf("After: pI = %p
        ", pI);
            
            for(i=0; i<10; i++)
            {
                printf("pI[%d] = %d
        ", i, pI[i]);
            }
            
            free(pI);
            free(pS);
            
            return 0;
        }
        
      • GCC 编译运行

        pI[0] = 0,pS[0] = 0
        pI[1] = 0,pS[1] = 0
        pI[2] = 0,pS[2] = 0
        pI[3] = 0,pS[3] = 0
        pI[4] = 0,pS[4] = 0
        Before : pI = 0x9241008
        After : pI = 0x9241438
        pI[0] = 0
        pI[1] = 0
        pI[2] = 0
        pI[3] = 0
        pI[4] = 0
        pI[5] = 0
        pI[6] = 0
        pI[7] = 0
        pI[8] = 0
        pI[9] = 0
        
      • VS 编译运行

        pI[0] = -842150451, pS[0] = 0
        pI[1] = -842150451, pS[1] = 0
        pI[2] = -842150451, pS[2] = 0
        pI[3] = -842150451, pS[3] = 0
        pI[4] = -842150451, pS[4] = 0
        Before: pI = 014B5650
        After: pI = 014B5650
        pI[0] = -842150451
        pI[1] = -842150451
        pI[2] = -842150451
        pI[3] = -842150451
        pI[4] = -842150451
        pI[5] = -842150451
        pI[6] = -842150451
        pI[7] = -842150451
        pI[8] = -842150451
        pI[9] = -842150451
        
  • 相关阅读:
    002梯度下降
    001-线性回归
    可视化库SEABORN基本操作2/2
    可视化库Seaborn基本操作1/2
    数据可视化库-Matplotlib基本操作
    数据分析处理库-pandas
    向量点乘(内积),叉乘(外积)
    科学计算库Numpy基础操作
    django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call
    ORM 模型
  • 原文地址:https://www.cnblogs.com/bky-hbq/p/13773697.html
Copyright © 2020-2023  润新知