关于C中的malloc和free的相关想法和实验##
本人刚入们数据结构这块,遇到不少关于内存管理这块的问题,做了一些实验,不是很确定,暂将这些想法和结果记录在这里,有误的地方大家勿喷,和大家一起讨讨论就好(哈哈哈),希望自己不断进步#__#
malloc函数可以从堆给分配一整块的存储空间,并返回这个片的首地址(void *),一般需要强制转化。如char* str = (char *)malloc(10*sizeof(char));
free函数是与malloc对应的函数,用于释放某个指针指向的空间区域,这片空间区域一定要通过malloc函数来分配。如接上free(str);
此时,原先str指向的空间被释放,从而可以成为下一次malloc的选取对象(我认为不能被malloc用于分配的这块内存是已经被占用(要是到结尾都没被释放,就是内存泄漏)),释放后,最好将str置空,因为释放并不影响str,会成为野指针,其内容是不确定的,要是再free一次将会崩溃。
实验:
typedef struct
{
char *name;
}PERSON,*PERSON_T;
void free1(PERSON* per)
{
free(per);
}
void free2(PERSON* per)
{
free((*per).name);
(*per).name = NULL;
}
int main()
{
PERSON person;
person.name = (char*)malloc(5);
memset(person.name,0,5);
memcpy(person.name,"yyb",strlen("yyb"));
printf("原始的串:%s\n",person.name);//显示yyb
free1(&person);
printf("释放错误的指针:%s\n",person.name);//显示yyb
free2(&person);
printf("释放正确的指针:%s\n",person.name);//显示null
}
产生上面的结果是因为free1(&person)函数释放一个不是malloc返回的指针,从main中看person相当是一个普通变量(内存是栈里的),没有实际释放name指针,所以仍然会显示yyb。
实验进阶:
typedef struct
{
void* data;
}STU,*STU_T;
typedef struct
{
char *name;
}PERSON,*PERSON_T;
void test(void * data)
{
STU_T stu = (STU_T)malloc(sizeof(STU));
stu->data = data;
free((PERSON_T)stu->data);
free(stu);
}
void my_free(PERSON_T per)
{
free(per->name);
}
int main()
{
PERSON person;
person.name = (char*)malloc(5);
memset(person.name,0,5);
memcpy(person.name,"yyb",strlen("yyb"));
printf("原始的串:%s\n",person.name);
test(&person);
printf("\n%s\n",person.name);
}
1:运行上面的代码会发现main中任然会显示yyb,原因还是因为test中 free((PERSON_T)stu->data);free(stu);
都没有实际释放到name.
将test修改后
void test(void * data)
{
STU_T stu = (STU_T)malloc(sizeof(STU));
stu->data = data;
free(((PERSON_T)(stu->data))->name);
free(stu);
}
这次main不显示yyb,说明真的释放了;
3:为了和在哪malloc,就在哪释放结合起来,现在需要把test的data指针回传给main函数,这里不考虑以返回值的形式,而是以参数传递的形式。主要改动了test和main
void test(void * data,void** value)
{
STU_T stu = (STU_T)malloc(sizeof(STU));
stu->data = data;
*value = stu->data;
free(stu);
}
int main()
{
PERSON person;
PERSON_T value = NULL;//用于接收回传指针
person.name = (char*)malloc(5);
memset(person.name,0,5);
memcpy(person.name,"yyb",strlen("yyb"));
printf("原始的串:%s\n",person.name);
printf("\n*****开始新的实验*******\n");
test(&person,(void**)&value);
free(value->name);
printf("\n%s\n",person.name);
}
这里有个疑问:为什么要用二级指针?以往都是通过传递一个一级指针给被调用函数,然后再被调用改变这个内容即可,但这里不同的是回传一个指针,设A是一级指针,*A= 一个指针通不过编译,是不被允许的,再者二级指针一种理解就可以理解为保存地址。
此外,还想附上其他一个例子:
void GetStr(char * s)
{
s=(char *)malloc(10*sizzeof(char));
memset(s,0,10);
memcpy(s,"i is not str",strlen("i is not str"));
}
int main()
{
char* str = NULL;
GetStr(str);
printf("%s",str);
}
结果并不是i is not str,因为s是str的一个副本,一开始都是NULL,但是s经过malloc后就直到别处了,而str任然指向NULL;
修改:
char* GetStr(char * s)
{
s=(char *)malloc(10*sizzeof(char));
memset(s,0,10);
memcpy(s,"i is not str",strlen("i is not str"));
return s;
}
在main中将GetStr(str)改为str =GetStr(str)即可;
或者通过将s以参数的形式回传回来,修改如下:
void GetStr(void** s)
{
*s = (char*)malloc(10*sizeof(char));
memset(*s,0,10);
memcpy(*s,"i is not str",strlen("i is not str"));
}
int main()
{
char* str = NULL;
GetStr(&str);
printf("%s\n",str);
}
虽然以二级指针回传,有些难理解,但是在后面的深入学习中我相信这一点会用到很多的,所以理解不了,强记要记下哦