free函数

1.free()函数

头文件:stdlib.h或malloc.h
作用:释放malloc(或calloc,realloc)函数给指针变量分配的内存空间


2.free的实现原理

操作系统在调用malloc函数时,会默认在malloc分配的物理内存前面分配一个数据结构,这个数据结构记录了这次分配内存的大小,在用户眼中这个操作是透明的。

那么当用户需要free时,free函数会把指针退回到这个结构体中,找到该内存的大小,这样就可以正确的释放内存了。


3.free到底释放了什么

free()释放的是指针指向的内存并非指针。指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的,所以说是垃圾。
注意:free()并不是真正意思上的释放内存:
其实,free函数只是将参数指针指向的内存归还给操作系统,并不会把参数指针置NULL。从另一个角度来看,内存这种底层资源都是由操作系统来管理的,而不是编译器,编译器只是向操作系统提出申请。所以free函数是没有能力去真正的free内存的。只是告诉操作系统它归还了内存,然后操作系统就可以修改内存分配表,以供下次分配。

通过这种内存分配机制,可以解释很多c语言中的迷惑问题:
比如,用户已经free了一段内存,为什么还可以调用该指针,并且编译器不报错?

因为,free函数的作用只是告诉操作系统该内存不用了,可以收回,操作系统就把该内存链接到链接表上,但是这段内存用户还是可以访问到的,只是该内存的值可能已经发生了变化。
即此时原本指向刚刚释放掉了空间的指针p仍然指向了该内存空间,这样一旦这段内存已经被别的变量使用的话,就可能误用p来修改这里的值。
解决办法就是,在free后,把该指针指向NULL。


4.浅识堆与栈

什么是堆:堆是大家共有的空间,分全局堆和局部堆。
全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。
什么是栈:栈是线程独有的,保存其运行状态和局部自动变量的。
栈在线程开始的时候初始化,每个线程的栈互相独立。每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈。栈空间不需要在高级语言里面显式的分配和释放。


5.free误区

free()的时候程序宕机,很多时候都是和内存溢出或者说内存分配问题有关(若遇到相关问题,可以多往这上面想):
一句话就是你想释放的内存和你实际释放的内存不一样。
举例一:

int shanchu(struct ListNode *head)
{

struct ListNode   *temp,*current;
int      i,j,ret=0;
if(head->next==0)
{
	ret=-1;
	return   ret;
}
i=bianli(head);
current=head->next;
temp=head->next->next;

for (j=0;jnext; 
}
head->next=0;
return   ret;

}
在销毁链表的时候,想把一个一个的数据节点所释放掉 ,但free()总是报错,为什么
因为在分配的时候,代码:struct ListNode *head = (struct ListNode *)malloc(sizeof(struct ListNode)); 上面只开辟了sizeof(struct ListNode )个内存,但是实际上节点被绑到其它数据块上了,它远远不止sizeof(struct ListNode)字节的内存,因此在释放上就会存在内存溢出的错误。

举例二:
函数:

   void Function(void) 
  
   { 
      
       char *p = (char *)malloc(100 * sizeof(char)); 
   } 

就这个例子,千万不要认为函数返回,函数所在的栈被销毁指针也跟着销毁,申请的内存也就一样跟着销毁了。这绝对是错误的!因为申请的内存在堆上,而函数所在的栈被销毁跟堆完全没有关系。所以,一定要记得释放!
事实上,如果你在函数上面定义了一个指针变量,然后在这个函数里申请了一块内存让指针指向它。实际上,这个指针的地址是在栈上,但是它所指向的内容却是在堆上面的。


6.关于free函数与malloc函数使用需要注意的一些地方:

A、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。
B、这两个函数应该是配对。如果申请后不释放就是内存泄露
(什么叫内存泄漏: 简单的说就是申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了);
如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会出现错误(释放空指针例外,释放空指针其实也等于什么也没做,所以释放空指针释放多少次都没有问题)。
C、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一些编译器的检查。

你可能感兴趣的:(C语言知识点归纳)