现在的位置: 首页 > 综合 > 正文

c的动态内存管理

2013年12月07日 ⁄ 综合 ⁄ 共 1716字 ⁄ 字号 评论关闭

关于c的动态内存管理一直是个经久不衰的话题,面试也是基本上都会考的,本来感觉已经明白了,但是今天使用的时候一不小心导致程序崩溃了,因此深入的去查了下资料,收获不少...贴出来与大家分享...

先贴个错误代码:

int * ptr = (int *)malloc(256);

ptr = ptr + 3;//对指针进行一个偏移操作

free(ptr);

这就是一段错误代码..?相信已经有人看出来错误在哪里了...如果不明白的继续往下面看...

先就这个错误讲解一下,free(ptr)函数释放内存的时候是需要从原先malloc()函数分配的地址那开始释放的,或者这样说,对malloc()的内存进行free()操作,是从当前的指针指向的地址开始释放有malloc()函数分配的大小的一块内存区域...因此,这样就需要你在进行free操作的时候,保证指针所指向的位置还是有malloc()分配出来的地址...那么如果你需要对malloc()分配出来的内存区域进行操作的话...就象下面这样...做个地址备份...

int * ptr = ( int *)malloc(256);

int * str = ptr;

str = str + 3;

free(ptr);//这样你释放就不会有问题了,也避免了内存泄漏.

OK,上面的问题和原理基本上已经说清了,虽然有点绕哈...下面是关于C的动态内存管理的一些稍微深入点的知识,有需要的可以看看...

malloc()分配的内存,实际上是分配的堆上面的内存,也就是说,你调用malloc()函数后,malloc()返回给你的是一个堆上面内存的指针,堆是大家共有的内存空间,分为全局堆和局部堆,局部堆呢就是用户已经分配了的堆空间,全局堆自然就是还没有分配的堆空间了.堆是在操作系统对进程初始化的时候分配的,你在程序执行的过程中,你也可以继续申请新的堆空间,但是需要用完后归还给操作系统,不然就是所谓的内存泄漏了...

那么栈则是线程独有的,用来保存程序的局部变量和运行状态的,在线程开始的时候进行初始化,每个线程的栈相互独立,速度很快,但是容量很小,既然是用来保存局部变量,那么肯定每个函数都有自己的栈,栈被用来在函数之间传递参数,操作系统切换线程的时候会自动切换栈空间,而且,在高级语言中,栈的分配和释放是不需要程序员来完成,操作系统会代替我们做这一部分工作...

操作系统中有一个记录空闲内存地址的链表,当你向操作系统申请内存的时候,会遍历该表,寻找第一个空间大于所申请的堆节点,然后将该节点从链表中删除,并将该块内存分配给程序.

所以,栈是由编译器自动分配和释放,保存函数的参数和局部变量等;堆则由程序员进行分配和释放,如果程序员不显示释放,程序结束后可能会有操作系统收回,所以,为了防止内存泄漏,一定要将动态分配的内存给释放掉...

这里需要区别的是局部变量和动态分配的内存的关系了...比如说:

//声明一个函数

char* test(char *test)

{

char * ptr = (char *)malloc(256);

test = ptr;

return test;

}

这里,实际上就是内存泄漏了,你调用一次就会分配一次(这个函数只是举例用,这里也确实不能free()--原因就自己想呢--呵呵),但是你没有释放由malloc()分配的内存,或者有的会问,不对啊...我程序调用结束后,所有的局部变量都会释放掉啊..?这是操作系统自己做的,所以,分配的内存肯定是回收了啊..?这里..请注意了...错了,malloc()分配的内存是没有回收的,因为,操作系统自动回收的是栈上的内容,但是你malloc()分配的是堆上的内存,那是需要你手动的回收的...所以即使函数调用结束,你堆上的内存也没有释放出来...因此,这就是在不经意间就造成的内存泄漏,也是对栈和堆的理解不透造成的...

free()函数释放的是指针指向的内存,而不是指针这个变量,指针是一个变量,只有程序结束时才会被销毁,释放了内存空间后,指向这块内存的指针还是存在,只不过在free()掉后,指向的内容是无效数据,是未定义内容,所以安全的做法是释放内存后,把指针指向NULL,防止指针在释放后又被重新使用--非常重要.

抱歉!评论已关闭.