一、内存分配
对于内存的分配,主要采用的是标记法。
分配方法有两种,一种是静态分配,也就是在程序编译的时候,就完成了对内存的分配。例如当一个数组在声明时,指定长度之后,它所需要的内存在编译时就会被分配。
另一种方法是动态分配,动态分配是指程序在运行时为它分配内存。
分配内存的时候,对于已分配的内存,操作系统会给一个标记,未分配的内存,操作系统也会有一个标记,操作系统辨别内存是否可以使用就是通过标记判断,当内存释放的时候,就会修改标记。
二、动态分配
C函数库关于内存的动态分配和释放提供了四个函数malloc、calloc、realloc和free。其中前三个是执行内存动态分配,最后一个是执行释放。
1、void *malloc(size_t size)
malloc函数所需要的参数是要分配的字节长度,例如
- int *p;
- p = (int *)malloc(100);
对于上面的代码,如果一个整数占有四个字节的话,将会分配25个整数的内存。为了增加代码的可移植性,如果要分配25个整数的内存,应将代码改为
- int *p;
- p = (int *)malloc(25*sizeof(int));
在malloc函数分配内存时,会从内存中提取一块合适大小的内存,并返回该块内存的首地址,这块内存并没有被初始化。对于这种方法,必然会有问题出现,就是可用内存的大小不能满足请求所需要的内存,此时,malloc函数返回NULL。所以,使用malloc函数分配内存之后,并不能保证内存分配成功,在使用的时候,应该先判断指针是否为NULL,如果不为NULL,则说明分配成功,可以使用。否则,反之。
2、void *calloc(size_t num_elements,size_t element_size)
calloc函数所需要的参数是元素的个数和元素的字节长度,之所以要这两个参数,是因为使用calloc函数在分配内存的时候,会对内存进行初始化,如果要初始化,就需要知道一个元素是多大,为了计算总的内存大小,还应该知道元素的个数。
calloc函数与malloc函数的主要差别就是在返回首地址的指针之前,对进行了初始化,如果在程序只是想将一些值存放到数组中,那么这个初始化就纯属浪费。
3、void *realloc(void *ptr,size_t new_size)
relloc函数需要的参数为原来内存的首地址新的内存的长度。
realloc函数用于修改已经分配内存的大小,使用这个函数可以将一块内存扩大或缩小。如果扩大一块内存,那么这块内存原先的内容必然会被保留,新增加的内存添加到原来内存的后面;如果缩小,对于尾部的内存会被释放。
对于扩大内存,依然存在内存不够的问题,如果分配不成功,就会返回NULL。除此之外,还有另一个问题,就是扩大内存的时候,不可修改原来内存的大小,此时系统将会重新分配一块内存,将原来内存的数据复制到新的内存中,所以使用realloc函数修改内存大小之后,应该使用realloc函数返回的指针而不是原来的指针。
4、void free(void *pointer)
free函数所需要的参数是一个指针,功能是将指针指向的内存区域释放(通过修改标记实现),以便内存可以重新使用。
free函数释放的只是指针指向的内存,指针所占用的空间并未被改变,调用free函数之后,指针所指向的地址仍然不变,如果在程序的后面,重新分配到了该指针指向的内存,使用现在的指针也可访问,但是不安全。此时,该指针被叫做野指针,为了避免野指针,应在调用free函数之后,将指针的值置为NULL。