zoukankan      html  css  js  c++  java
  • C语言-malloc,calloc,realloc 函数的使用(堆空间的使用)

    内存中的五大区域

    • 栈:存储局部变量
    • 堆:程序员手动申请的空间
    • BSS 段:未初始化的全局变量,静态变量
    • 常量区:已经初始化的全局变量,静态变量
    • 代码段:存储代码的

    如何向堆区申请字节空间来使用

    • 1 我们在堆中申请的字节空间,如果不主动释放,那么系统就不会释放的,除非程序结束了

    • 在堆中申请字节空间的步骤

      • 申请
      • 使用
      • 释放
    • 如何在堆区申请指定字节数的空间呢?

      • malloc()
      • calloc()
      • realloc()
      • 这三个函数是放在 stdlib.h 的系统头文件当中,这三函数是和申请字节空间有关的
    • malloc 函数

      • 参数只有一个:size_t 类型,也就是 unisigned long 类型的
      • 作用:向堆空间申请指定字节的空间来使用
      • 参数代表的意义:向堆内存申请多少个连续的字节空间
      • malloc(4) 向内存中申请连续的四个空间
      • 返回值:是 void*,代表没有类型的指针,返回的是创建的空间中第一个字节的地址
      • 只是反悔了第一个字节的地址,么有说这个指针是什么类型的
      • 我们应该使用什么类型的指针变量来保存 malloc 函数返回的地址呢?
        • 用什么类型的指针去接,
        • 如果你想一个字节一个字节的操作,那么就是用 char 指针
        • 如果你想四个字节四个字节的操作,那么就用 int 指针
        • 如果你想八个字节八个字节的操作,那么就用 double 指针
        • 如果你想四个字节四个字节的操作,还是单精度浮点操作,那么就用 float 指针
        • 关键在于你想怎么怎么用这个申请的变量
          // malloc()函数
          int * num = malloc(24); // 在堆中申请连续的四个字节空间,并将第一个字节的地址返回来,所以要用指针接收
          
          num[0] = 1;
          // int len = sizeof(num) / sizeof(int);
          for (int i = 0; i < 6; i++) {
              num[i] = i;
          };
          
          for (int i = 0; i < 6; i++) {
              printf("num[%i] = %i
      ",i,num[i]);
          };
          *(num) = 1;
          *(num+1) = 2;
          *(num+2) = 3;
          *(num+3) = 4;
          *(num+4) = 5;
          *(num+5) = 6;
          // 可以使用[]号对其赋值,或者使用指针与整数的加减法对其进行赋值
          // 这样可以对申请的 24 个字节空间以四个字节为一个单位进行赋值,
      

    image-20200612133443090

    • 在堆区申请的字节空间是从低地址向高字节地址分配,每次申请的字节并不是连续的
    • 每次申请的字节地址都是从 0 开始,但是每一次申请的指定个自己,这些字节肯定是连续的
        int * num = malloc(4); // 在堆中申请连续的四个字节空间,并将第一个字节的地址返回来,所以要用指针接收
        int * num1 = malloc(4);
        int * num2 = malloc(4);
        printf("num的地址:%p
    ",num);
        printf("num1的地址:%p
    ",num1);
        printf("num2的地址:%p
    ",num2);
        
    // 输出内容:
    num的地址:0x1007311a0
    num1的地址:0x10072ef60
    num2的地址:0x10072d6e0
    
    • 申请的堆空间地址,是有默认值的,默认值为垃圾值,不会自动清零
        int *num = malloc(12);
        for (int i = 0; i < 3; i++) {
            printf("num[%i] = %i
    ",i,*(num+i));
            printf("num[%i]的地址:%p
    ",i,&num[i]);
        }
    
    • 在向堆区申请字节空间的时候,有可能会申请失败,如果申请失败,返回的指针就是 NULL 指,所以我们申请完后最好判断下是否申请成功
        // 如果申请失败返回的指针是NULL,所以申请完最好自己判断下是否成功
        int* num = malloc(12);
        num[0] = 1;
        num[1] = 2;
        num[2] = 3;
        if(num != NULL){ // if(num)也可以,null 代表的就是 0,如果不是 0 那么就进入
            for (int i = 0; i < 3; i++) {
                num[i] = num[i] * 100;
            }
            
            for (int i = 0; i < 3; i++) {
                printf("num[%i] = %i
    ",i,num[i]);
            }
        }
    
    • 申请的空间一定要记得释放,调用函数 free(),释放堆空间,如果没有写的话程序结束才会结束掉
    free(num);
    

    calloc 函数

    • 跟 malloc 函数是一样一样的
    • 格式:
      • 参数 1:多少个单位
      • 参数 2:每一个单位的字节数
      • calloc(4,sizeof(int));表示申请 4 个 int 类型的空间
        // calooc 函数
        int *num = calloc(3, sizeof(int)); // 申请三个,int 类型的空间地址
        if(num){
            for (int i = 0; i < 3; i++) {
                num[i] = i * 10;
            }
            
            for (int i = 0; i < 3; i++) {
                printf("num[%i] = %i
    ",i,num[i]);
            }
        }
        
    
    • calloc与 malloc 函数相比的优势
      • calloc 申请的字节,申请完之后,系统会将字节中的数据清零
        // calooc 函数
        int *num = calloc(3, sizeof(int)); // 申请三个,int 类型的空间地址
        if(num){
            
            for (int i = 0; i < 3; i++) {
                printf("num[%i] = %i
    ",i,num[i]);
            }
        }
    
    // 控制台输出
    num[0] = 0
    num[1] = 0
    num[2] = 0
    

    realloc 函数

    • 作用:扩容
    • 注意:我们有了指针,几乎就可以操作内存上的每一个字节,但是我们还是建议不要乱来,只操作我们申请的字节空间,因为有可能会出现一些问题
    • 当我们发现我们之前在堆区申请的字节空间不够用的时候,那我们就可以用 realloc 进行扩容
    • realloc(p1,4);
        int * num1 = realloc(num, 4);// 发现 calloc 申请的 3 个 int 类型空间不够用了,那么就用 realloc 进行扩容
        // 如果 calloc 申请的3e个 int 类型空间后面的地址够用,那就跟着后面申请
        // 如果 calloc 申请的 3 个 int 类型空间后面的地址不够用,那就在堆区重新找一块地址,并且将原来 calloc 申请的地址复制过来,并将低字节地址返回
        if(num1){
            for (int i = 0; i < 4; i++) {
                num1[i] = i * 10;
            }
            
            for (int i = 0; i < 4; i++) {
                    printf("num1[%i] = %i
    ",i,num1[i]);
                }
            free(num1);
        };
    
  • 相关阅读:
    【测试平台学习1】 vue使用与启动
    【Devops】 发布一个Python项目(Flask服务后端)到K8S环境
    Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理
    Spring5源码分析(023)——IoC篇之bean加载:从缓存中获取单例 bean
    Java基础(018):Class.forName和ClassLoader的区别
    Spring5源码分析(022)——IoC篇之bean加载:FactoryBean的用法
    Spring5源码分析(021)——IoC篇之bean加载
    Java基础(017):反射初探
    Java基础(015):泛型
    Java基础(001):关于 short i = 1; i += 1;
  • 原文地址:https://www.cnblogs.com/shanshan-test/p/13110986.html
Copyright © 2011-2022 走看看