一般在主函数中(main)使用malloc函数,然后在通过free函数进行释放内存,但有时候如果必须在子函数长调用malloc函数该怎样进行内存释放呢?在这里进行一下总结:
首先我们先来了解一下malloc函数的含义:
malloc函数是为指针变量或数组分配某个可用空间的首地址,所以当分配一个首地址给一个指针变量时,这个指针变量指向的内容就发生了改变,指向了由malloc分配的那一块空间。如果要想改变一个指针变量的指向,在子函数中就要传递这个指针变量的地址,而不是它指向的空间。
有一种不合理的解释,但这可以帮助我们理解在子函数中调用malloc函数形参传递的含义,当我们传递一个指针指向的值时(其实是某个变量的地址或某个地址[如NULL]),malloc就给这个值分配了一块空间而不是给我们所想的那样给主函数中的指针变量开辟一块空间。如主函数中有char*p=NULL;那么此时在子函数中就位以NULL[(void*)0]为地址(也是指针只是是个固定值的指针)的空间分配了一块空间,而并没有改变p所指向的空间。
方式一:使用二重指针(在这里了使用网络上的一段程序进行解释(有点懒同时也为了节省时间,哈哈))
#include <stdio.h>
#include <stdlib.h>
/* 参数使用地址方式传入 */
void create(char **str)
{
*str = (char*) malloc(sizeof(char) * 20); //此处str参数接收的是指针变量的地址,而不是指针指向的地址,待子函数执行过后,指针的地址没变,并且指向了malloc分配空间的首地址(堆),
//此时由于指针的地址一直都是从主函数传递过来的地址,所以主函数中的str所指向的地址同时发生了改变,指向了malloc分配空间的首地址.
scanf("%s", *str);
}
int main(int argc, char **argv)
{
char *str=NULL;
/* 参数使用地址方式传入 */
create(&str); //此处传递的是指针的地址,而不是指针所指向的地址(即NULL=(void*)0),
puts(str);
free(str);
return 0;
}
在此可能某些人会有所疑问,问什么不能直接用指针进行解决呢?归根结底是c语言的参数传递都是值传递,若传递的只是指针变量,传递的只指针变量的值,而不是指针本身,这样写就有点绕了,好了下面咱们用例子加以说明(我也比较看例子,呵呵!)
借用山上面的程序一用:
#include <stdio.h>
#include <stdlib.h>
/* 参数使用地址方式传入 */
void create(char *str)
{
str = (char*) malloc(sizeof(char) * 20); //此处str接收的只是指针指向的地址(如本例为NULL),
//待子函数执行中,形参str指针变量指向了malloc分配内存的首地址,子函数执行后,形参由栈str释放,而main函数中的str还是等于NULL,并没有改变。
scanf("%s", *str);
}
int main(int argc, char *argv[]) //在这里为了和上面的程序少许不一样,稍作改动,本质还是一样的( char *argv[]=char **argv),可以多学点东西,好开心!!!!!!。
{
char *str=NULL;
create(&str); // 参数使用地址方式传入 ,此时传递的是指针指向的地址(NULL即地址0),而不是传递的指针的地址
puts(str);
free(str);
return 0;
}
方式二:换个程序吧,此方法是借助于临时指针变量或通过计算出由malloc分配空间首的地址,返回给主函数中的指针变量(p);
/*字符复制函数*/
char * strcpy1(char * dest, const char *src)
{
//assert((dest != NULL) && (src != NULL)); //标准库函数
dest = (char *)malloc(strlen(src)+1);
if (NULL == dest)
{
printf("内存分配失败\n");
exit(1);
}
//char a = (strlen(src) + 1); //用自加后的dest减去a得到dest的首地址,即malloc分配的首地址,由于下面用了临时指针变量保存dest的首地址,所以在这里就用不着了,O(∩_∩)O哈哈~
if (NULL == dest || NULL == src)
printf ("Invalid argument(s)");
char *tmp = dest; // 用来存储dest的首地址,因为下面dest要进行自加,dest就不咋指向malloc分配的首地址了,所以需要记录下dest的首地址,以便进行释放内存
printf("dest2地址=%p\n", dest );
while ((*dest++ = *src++) != ‘\0‘); //赋值表达式返回左操作数,所以在赋值‘\0‘后,循环停止。这句很是经典啊!谨记!
return tmp ; //此句等价于return (dest- a);
}
int main(void)
{
char *p = NULL;
const char *p1 = "123456789";
printf("p2地址=%p\n", p);
if (NULL == p)
{
printf("内存分配失败\n");
}
p=strcpy1(p,"123456"); //通过函数返回指针来改变p的值
free(p);
p = NULL;
return 0;
}
总结:在进行子函数调用free时,只要遵循一个原则:想方设法将malloc分配空间的首地址返回给主函数的指针变量即可在主函数中进行内存的释放。
作者:Kai-Ming Guo
链接:https://www.zhihu.com/question/43612699/answer/96290581
来源:知乎
著作权归作者所有,转载请联系作者获得授权。