内存存储模型:根据操作对象(变量、数组等)是否已知所需的存储空间可分为静态存储分配和动态存储分配。
一、静态存储分配:通常定义了一个变量后,编译器就可根据其数据类型知道该变量所需内存空间的大小,从而系统会在运行程序时为其分配确定的存储空间。
二、动态存储分配:有些操作对象只有在程序运行时才能确定,此时编译器不能知道他们需要多大的内存空间;因此,在程序运行时,系统会根据用户的要求分配存储空间且由用户决定何时释放该内存空间。这个分配方式充分利用了内存空间,还可减少了由于操作对象不确定的情况下造成的浪费和给用户提供了灵活性。所有的动态存储分配都在堆区进行。
(1)动态内存分配函数:
①void *malloc(size_t size):调用该函数后,会在内存的“堆”中分配一个连续的size个字节的存储区,若分配成功则会返回指向该存储区首地址的void型指针(通用指针),在实际运用时需要将该指针强制转换成具体类型的指针,以实现对具体数据的操作,若分配内存失败(堆空间不足)则返回空指针(NULL)。函数本身并不识别要申请的内存是什么类型,而只关心申请内存的总字节数。
int *p;
p=(int*)malloc(N*sizeof(int));//p指向N个整型数据长度的堆空间
②void *calloc(size_t nmemb, size_t size):该函数用法与malloc()类似,参数nmemb表示建立存储区的单元数,size表示每个单元所占的字节数,因此调用该函数将分配nmemb*size个字节的存储空间。
int *q;
q=(int*)calloc(N,sizeof(int));//q指向N个整型数据长度的堆空间
(2)动态内存释放函数:
void free(void *ptr):调用该函数后将释放指针ptr指向的由动态内存分配函数产生的内存空间。
int *p;
p=(int*)malloc(N*sizeof(int));//p指向N个整型数据长度的堆空间
free(p);//释放p指针指向的堆空间
p=NULL;//不使用时置为0
注:
①free(NULL)的话没有任何效果,且free的指针不能是非malloc函数产生的指针。
②free(ptr)实际表示删除了ptr指向的目标(变量、数组等),释放了目标所占的堆空间(默认全部置为0),并没有删除ptr指针,后面的语句任然可以使用该指针,若不再使用该指针的话要置为NULL,否则将变成“野指针”,可能会导致严重后果。
③malloc、calloc应与free函数配对使用,无需再使用的内存应当及时释放回收,动态分配的内存只要不释放将一直存在,即使该调用函数结束后仍可使用建立的动态对象。
④要妥善保存好动态分配函数返回的指针,避免丢失指针造成内存泄漏;另外,不能重复释放同一块内存空间,因为有可能该空间已被另分配给别的目标使用了。
注:
1.释放一个已分配的数据块,只是对此数据块以及其前后数据块的控制块头部(链表)进行调整,并没有对实际有效数据区域(用户可见的区域)进行初始化操作,也就是说数据区域中的数据保持不变。
2.malloc后没有free掉的内存就不能再分配了(内存泄漏)。
3.free了指针之后,只是释放了指针指向的堆内存(操作系统可以把该堆内存继续分配出去),但是指针的值(指针指向的空间)不变,用原来的指针仍然可以访问该内存且不报错。所以要注意如果该内存又被malloc出去了,可能会被原来指针的内容覆盖。如下图。
以上函数包含在stdlib.h头文件里。
如有疑问或者建议,欢迎大家提出和讨论呀!!!