7.动态内存

2 阅读3分钟

内存

程序内存的分布

一个程序正在运行的时候,内存有以下分布(五大区):

  • 栈区(stack)filo先进后出
    • 用来存储函数运行时的临时信息的结构、分配的局部变量、函数的参数、返回值数据、返回地址。这些数据会在函数运行结束后被系统清空。
  • 堆区(heap)fifo先进先出
    • 一般是由程序分配和释放的,用来存储程序运行时分配的变量的。
  • 全局区(静态区static)
    • 存储全局变量、静态变量,程序结束后由系统释放。
    • 全局区分为:已初始化全局区(.data段)和未初始化全局区(.bss段)
  • 常量区(.rodata)只读
    • 存储常量字符串,程序结束后由系统进行释放
  • 代码区
    • 存储函数体(类成员函数、静态函数、全局函数)的二进制代码

注意:栈区和堆区在内存中是对向存储的,如果调用函数、变量等使用太多内存,使用的内存是有可能碰到的,可能会栈溢出。

动态内存分配

不由系统分配内存,而是由程序员分配内存(只有堆区需要)

malloc      calloc        realloc       free
分配内存     分配数组内存   重新分配内存   释放内存
  • malloc

    memory allocate: 开辟一个内存空间

    void *malloc(size_t size);
    size: 传入需要分配的内存大小,字节
    返回值:
        如果分配成功,返回分配空间的首地址
        分配失败,返回NULL
    

    之所以返回void,是让程序员自己去定义类型

    • 分配到:堆区
      • 堆区,一旦分配了内存,如果不手动释放,那么该内存会一直存在,直到进程退出
      #include <stdio.h>
      #include <stdlib.h>
      
      int main(){
          // 以前使用
          int a = 100;
          int *p1 = &a;
      
          // 使用:动态内存分配
          int *p = NULL;
          p = (int *)malloc(sizeof(int));
          *p = 10;
          int b = *p;
          printf("a=%d, b=%d", a, b);
          free(p);
          p = NULL;
      
          return 0;
      }
      
      注意:如果在非main的函数中不使用malloc分配的内存,在函数结束时内存就会释放了。所以如果想要让内存保持,就要使用 malloc,malloc分配的内存不用的时候必须要free掉
  • free 释放动态内存分配的内存

    int *p = (int *)malloc(sizeof(int));
    *p = 100;
    printf("%d\n", *p);
    free(p);
    p = NULL;
    

    free只释放堆内存(动态内存分配的内存),不要释放局部变量内存

  • calloc

    cell allocate: 用来分配一段空间,用来存储数组

    void *calloc(size_t nmemb, size_t size);
    作用:
        用来分配一段空间,来存储数组
    memb:
        用来存储数组元素的个数
    size:
        用来表示数组元素的大小
    返回值:
        内存分配成功后,返回内存的首地址
        内存分配失败,返回NULL
    
    calloc(n, size))  <===> malloc(n*size);
    
    // 要想创建一个 int [10] 数组的空间
    calloc(10, sizeof(int));
    
  • realloc

    repeat allocate: 重新分配开辟的动态内存大小

    void *realloc(void *ptr, size_t size);
    作用:
        重新分配传入指针指向的空间大小
    ptr:
        需要重新分配内存的内存首地址
    size:
        重新分配的内存大小
    

    用法:

    int *ptr = malloc(10000);
    int *new_ptr = realloc(ptr, 5000);
    if(new_ptr){
        ptr = new_ptr;
    }
    
    • 改变ptr内存大小后,ptr的原内容不变,无需重新初始化
    • 如果ptr==NULL, 那么 realloc(NULL, size) 等价于 malloc(size);
    • 如果ptr!=NULL 且 size==0, 那么 realloc(ptr, 0) 等价于 free(ptr);

    注意:尽量避免缩小空间,可能会导致数据异常和性能问题。