分类: C/C++
2009-09-20 10:55:48
为什么要使用动态内存分配
我们以数组为例,在我们声明一个数组时,必须用一个编译时常量指定数组的长度。但是常常这个数组的长度不是固定的或是未知的,也就是说数组的长度只有在运行时才会知道具体是多少?应该为他分配多少内存。
一般人们面对这种未知长度的数组常采用的方法是声明一个较大的数组,自以为这样就不会在发生数组溢出的问题,但随着科技的发展你有可能会遇到要求更大的数组,这时候你再来修改的程序吗?还有如果在一个程序运行中数组的个数有时很大而有时很小的时候,我们就要考虑我们内存的利用率了,尤其是从事我们嵌入式这一行的,本身可利用的内存就不多,所以内存的利用率对我们来说是极为的重要!所以我们在编写程序时必须考虑数组会不会有溢出的情况!
对于这种情况我们可采用另一种方法来在程序运行时动态的为他分配所需的内存。
通过上面的简单分析,我们应该对为什么要采用动态内存分配有一个初步的认识了!下面我们就来看看在C中是如何来进行动态内存分配的!
我们首先来看两个函数malloc和free
这两个函数是c函数库提供用来执行动态内存分配和释放的函数。这些函数维护一个可用的内存池。当一个程序需要内存时就可以调用malloc函数,该函数可以从内存池中提取一块合适的内存,并向调用者返回一个指向这块内存的指针。注意调用这个函数并没有以任何方式对这块内存进行初始化。如果需要的话必须手动对这块内存进行初始化,这时可以使用memset函数来对这块内存进行填充。
#include
void *
malloc(size_t size);
malloc()用来配置内存空间,其大小由指定的 size决定。
void p = malloc(1024);
memset(p,0,sizeof(p));
另一种方式就是采用函数calloc来进行内存的分配。
void
*calloc(size_t nmemb,size_t size);
calloc()用来配置 nmemb 个相邻的内存单位,每一单位的大小为size,并返回指向第一个元素的指针。这和使用下列的方式效果相同:malloc(nmemb* size);不过,在利用calloc()配置内存时会将内存内容初始化为 0。
当调用free时,将分配的这块内存归还给内存池。
void free(void
*ptr);
参数 ptr 为指向先前由 malloc() 、calloc()或 realloc()所返回的内存指针。调用 free()后 ptr 所指的内存空间便会被收回。假若参数 ptr所指的内存空间已被收回或是未知的内存地址,则调用 free()可能会有无法预期的情况发生。若参数ptr为NULL,则free()不会有任何作用。
注意这些函数的原型都是在stdlib.h这个文件中的。
malloc的参数就是需要分配的内存字节(字符)数,如果内存池中的可用内存可以满足这个需求,malloc就直接返回一个指向被分配内存块起始位置的指针。malloc所分配的内存是连续的,不会分开位于两个或多个不同的内存。同时malloc实际分配的内存可能比你要求的多一点,这是由编译器来定义的。
如果内存池是空的或他的可用内存无法满足你的请求时,malloc函数会向操作系统请求,要求得到更多的内存,并在这块新内存上执行分配任务。当然如果操作系统无法向malloc函数提供更多的内存,那么malloc就只好返回一个NULL指针。所以在调用malloc来分配内存时,必须对返回值进行检查,确保返回的不是NULL指针,才可以继续向下操作。
既然free函数和malloc、calloc等执行的是相反的操作,我们也很容易想到,那么free的参数,也必须时malloc、calloc等的返回值,或者是一个NULL指针。当然如果是null指针的话free函数是不会产生任何效果的。
下面来看看这个函数calloc
void
*calloc(size_t nmemb,size_t size);
前面也已经讲过了这个函数和malloc的一个不同是,它在返回内存指针之前就已经将分配的内存全部初始化为零。这一点有些时候是有用的,但也不尽然,要看具体的情况,一般就算是需要初始化使用malloc和memset的时候也是比较多的。这两个函数之间还有另一个区别:请求内存的方式不同。我们从calloc的参数中可以看到,包括元素的数量和每个元素的字节数。calloc请求的内存是根据这些值来计算出来的。
还有一个函数我们前面没有介绍realloc,这个函数和前面两个不同,它适用于修改一个原先已经分配的内存块的大小。当我们需要使一块内存块扩大或缩小时可以调用这个函数。如果用于扩大一个内存块,那么这块内存原先的内容依然保留,新增的内存添加到原先内存块的后面,需要注意的是新内存块并没有以任何方式进行初始化。相反如果用于缩小一个内存块,那么这个内存原来尾部的内存便被删除,但是剩余部分内存的原先内容依然保留。
如果原先内存块的大小是无法改变的那么realloc将从新分配另一块指定大小的内存块,并把原先那块内存的内容复制到新的内存块上面。所以在使用了realloc之后便不可以再使用原来指向那块旧内存的指针了,而应该使用realloc所返回的新指针。否者很容易出错!
另一个需要注意的就是如果realloc函数的第一个参数设为NULL那么它和malloc的行为是一样的。
好了今天有关动态内存分配的知识,就先讲到这。下次我们就开始讲如何使用这些函数来进行动态内存的分配。
小孟在此感谢各位的支持!