《C Primer Plus》学习笔记之 C内存管理

第六种存储模型-动态内存分配

对于在C数据的属性(二)存储类一文中提到的五种存储类型,在决定了使用哪一种之后,就自动决定了作用域和存储时期,服从预先制定的内存管理规则。
除此之外,C还提供了第六种更灵活的内存管理方式-基于库函数的动态内存分配

  • 内存分配函数malloc()
    • 函数malloc()接受一个参数:所需内存字节数。然后malloc()找到可用内存中一个大小合适的块,它并不给内存块分配名字,只返回内存块第一个字节的地址。通常配合指针变量来使用malloc(),ANSI C中malloc定义为指向void的通用指针,可以将它的返回值指派给指向任意数据结构的指针。
    • 若malloc()找不到可用内存,它将返回空指针。
/*这段代码请求30个double类型值的内存空间,并把ptd指向内存空间所在位置*/
double *ptd;
ptd = (double *)malloc(30 * sizeof(double));    //建议使用(并非强制)类型指派运算符(double*)
                                                //1、使程序清晰2、兼容C++
  • calloc()
    • calloc()接受两个参数(都是无符号整数,ANSI C中为size_t类型):第一个参数是所需内存单元的数量,第二个参数是每个单元以字节计的大小
    • calloc()将内存块中的所有位都置为0(注意在有些硬件系统中,浮点值0不是用所有位为0 来表示的)
/**/
long * newmem;
newmen = (long *)calloc(100,sizeof(double));
  • 函数free()
    • 函数free()接受一个参数:malloc()/calloc()返回的地址,即指向malloc()/calloc()分配的内存块的指针。该函数释放malloc()/calloc()分配的内存
    • 不能使用free()来释放通过其他方式(比如声明一个数组)分配的内存。
    • 对应每个malloc()/calloc()调用,都应调用一次free(),否则可能出现内存泄露(memory leak)问题。

设想malloc()/calloc()和free()管理着一个内存池,每次调用malloc()/calloc()从池中分配内存给程序使用,每次调用free()将内存归还到池中,使内存可以再次使用。

【总结】创建一个数组的三种方法

  • 声明一个数组,用常量表达式指定数组维数,用数组名访问数组元素
  • 声明一个变长数组(VLA),用变量表达式指定数组维数,用数组名访问数组元素(C99新特性)
  • 声明一个指针,调用mallo()函数分配内存,然后使用该指针访问数组元素

VLA与malloc()的异同比较

  • 相同点
    两种方法都可以创建一个动态数组(dynamic array),即一个在程序运行时才分配内存并可在程序运行时选择大小的数组。
  • 不同点
    • VLA具有自动存储时期,即在程序运行完定义VLA的代码块之后VLA所占的内存空间会自动释放
    • 通过malloc()分配内存空间创建的数组并不具有自动存储时期,数组的使用并不局限于一个代码块中,通过指针可以供需要对该数组进行操作的函数使用。要释放该数组所占的内存空间,必须调用free()函数。

C的内存管理

C内存管理的理想模型:
程序将可用内存分成三个部分:

  • 静态变量(具有外部链接、内部链接或空链接)所占内存
    • 这部分内存在程序编译时就已经分配了,其持续时间从程序开始到程序结束。
  • 自动变量所占内存
    • 这部分内存在程序进入变量定义所在代码块时分配,在程序退出该代码块释放。
    • 这部分内存一般处理为一个堆栈(后入先出)。
  • 动态分配内存
    • 这部分内存在调用malloc()/calloc()时分配,在调用free()时释放。
    • 这部分内存由程序猿而不是一系列固定的规则控制内存的持续时间,可能在一个函数中分配,在另一个函数中释放,使得这部分内存可能变成碎片状,即在活动的内存块直接散布着未使用的字节片。
    • 使用动态内存往往导致进程比使用堆栈内存慢。

你可能感兴趣的:(C语言)