1 ,先来一张内存分配图:
主要的内存模型和Java的差不多。参考 http://blog.csdn.net/hadoopx/article/details/9123903 之前写的一篇 java的内存分析。
2 ,对几个内存分配函数的理解。
1,malloc和calloc函数
功能:动态内存分配函数
头文件:#include<stdio.h>
原型:void * malloc(size_t size);
void * calloc ( size_t num,size_t size ); //size 分配内存的大小,num 分配内存的块数。
返回值:成功返回分配内存的首地址,失败返回null;
区别:malloc 和calloc 都可以进行内存的分配,但malloc 只能一次分配一块内存,而且不初始化所开辟的内存区,
calloc可以开辟连续的内存,并且把所开辟的内存区初始化为数字0。
void testmalloc()
{
//p指针在栈里面
//malloc(sizeof(int))开辟的内存在堆里面
//malloc没有对开辟的内存进行清0处理
int *p = malloc(sizeof(int));//如果不释放:导致内存泄露 p指向开辟内存的首地址。
if(p!=NULL){//保证p在指向一块开辟成功的堆内存
*p=123;
printf("*p = %d",*p);
free(p);
p=NULL;//导致野指针的问题
}
else
{
exit(1);
}
}
void testcalloc(){
// int t[5]
//开辟一块连续的内存,相当于数组。
//对开辟的内存进行清0的处理,可能有上一次遗留的垃圾值。
int *p = calloc(5, sizeof(int));//4*5 20字节
if(p!=NULL){
// for (int i = 0; i<5; i++) {
// *(p+i) = i+2;
// }
for (int i = 0; i<5; i++) {
printf("t[] = %d \n",*(p+i));
}
free(p);
p=NULL;
}else{
exit(1);
}
}
2。free函数。
功能:释放内存。
头文件:#include<stdlib.h>
函数原型:void free(void *ptr);
参数 :ptr是使用malloc和calloc 等内存分配函数所返回的内存首字节地址。
返回值 :无
free和野指针的问题:
指针被free之后,没有设置为NULL,让人误认为p是个合法指针,别看已经free了,他只是释放了他所指向的堆内存的空间。
而自己依然存在(如果没有超过在所在的函数体),通常会用if(P!=NULL)进行预防处理。
但是没有什么效果,因为p不是空指针,但也不指向合法的内存。
要解决这个问题,再free之后,直接把free的指针设为null;
3,reallco函数
功能:更改已经配置的内存空间,即更改由malloc()函数分配的内存空间的大小。
原型:realloc(void * ptr, size_t size);
如果分配的内存减少,realloc仅仅是返回原指针。
如果size=0, 则是等价于释放内存。
如果内存扩大,
1),如果当前内存后面又需要的内存空间,则直接扩展这段内存空间,realloc返回原指针。
2) ,如果当前内存段后面的空闲字节不够,重新找一块能满足这个要求的内存块,将原数据copy到这块内存。并将原来的释放的,返回新的内存块地址。
3), 申请失败,返回null ,原来的指针仍然有效。
void testrealoc()
{
int *p1 = malloc(5*sizeof(int)); //20个字节开辟一块连续的内存,相当于数组。但是不清零。开多少用多少,不能越界。发生系统崩溃。
if(p1!=NULL){
for (int i = 0; i<5; i++) {
*(p1+i) = i+2;
}
int *p2 = realloc(p1, 10);//10个int类型,40字节。把p1前20个字节copy到前5个int中。
//对后面的五个int 进行初始化
for (int i = 5; i<10; i++) {
printf("i = %d \n",i);
*(p2+i) = i+5;
}
for (int i = 0; i<10; i++) {
printf("p2 = %d \n",*(p2+i));
}
free(p2);
p1 = NULL;
p2 = NULL;
}
}
总结:不管只用哪种方式,开辟内存,都要把内存释放掉。尽量在哪里使用就在哪里释放。
文章内容来源为尚学堂夏云中老师的C语言课程。