版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hnxyxiaomeng/article/details/84793462
1. 子函数malloc分配内存
为了增强程序可读性,有时会在子函数中malloc分配内存。测试了如下三种方法,容易想到的是第一种。事实证明这种也是错误的!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct _dataStc
{
int buf[100];
int size;
}dataStc;
void func1(dataStc* p)
{
p = (dataStc*)malloc(sizeof(dataStc));
p->size = 10;
return;
}
dataStc* func2(void)
{
dataStc* p;
p = (dataStc*)malloc(sizeof(dataStc));
p->size = 10;
return p;
}
void func3(dataStc** p)
{
*p = (dataStc*)malloc(sizeof(dataStc));
(*p)->size = 10;
return;
}
int main(int argc, const char * argv[]) {
dataStc *p1 = NULL;
dataStc *p2 = NULL;
dataStc *p3 = NULL;
func1(p1);
p2 = func2();
func3(&p3);
if (p1 == NULL)
{
printf("p1=NULL\n");
}
else
{
printf("p1->size:%d\n", p1->size);
}
if (p2 == NULL)
{
printf("p2=NULL\n");
}
else
{
printf("p2->size:%d\n", p2->size);
}
if (p3 == NULL)
{
printf("p3=NULL\n");
}
else
{
printf("p3->size:%d\n", p3->size);
}
return 0;
}
执行结果如下所示:
p1=NULL
p2->size:10
p3->size:10
结论:只有后两种方法能正确分配内存。即直接返回内存指针,或将二级指针作为参数传入子函数。这是因为,在子函数中,内存指针只是被当做一个变量来处理的(虽然这个变量被定义为dataStc *),对其赋值后再返回,它的值当然没改变。
另外,由于成员选择运算符“->”的优先级比取值运算符“*”高,所以在func3中,*p需要加括号。
2. 子函数free释放内存
在子函数中释放内存,很容易想到的是写个下面这样的函数释放内存:
void func_free(dataStc* p)
{
free(p);
return;
}
上面的函数能释放内存,但也有个缺陷。因为C在free一段内存后,该内存的确是被释放了(可以被其他程序使用),但指针p仍然指向该段内存(而不是我们期待的NULL)。这时p就成为野指针了(不同于空指针),仍然可以访问或修改p指向的内存。如果其他程序不慎又通过p访问了内存,程序或许不报错,但可能带来不可预知的后果。
因此,保险做法是,在free后,将p赋为NULL。由于这里又将输入变量p修改了,因此仍然需要传递二级指针。正确的代码为:
void func_free(dataStc** p)
{
free(*p);
*p = NULL;
return;
}
这样,在其他程序中访问p时,就可先判断其是否为NULL了。