我写了下面的代码示例:
#include <stdio.h>
#include <stdlib.h>
char *test(void);
int main()
{
char *base_ptr = NULL;
base_ptr = test();
for (char i = 0; i < 5; i++)
{
printf("base_ptr[%hhi] = %hhi\n", i, base_ptr[i]);
}
free(base_ptr);
return 0;
}
char *test(void)
{
char *local_ptr = NULL;
local_ptr = (char *)malloc(5*sizeof(char));
for (char i = 0; i < 5; i++)
{
scanf(" %hhi", &local_ptr[i]);
}
return local_ptr;
}
所以,我知道一旦被“malloc()”或“calloc()”分配,我必须使用“
free()
”函数释放分配的内存。
在我展示的代码示例中,我在函数“test”中进行分配,它返回一个指针。返回的指针携带分配数组的基地址。在函数“
test()
”中没有使用函数“free()
”,因为到达返回运算符,程序离开了函数,这导致从函数本身释放内存,所以从它的所有局部变量,包括保存基地址的指针。
但是在函数“
main()
”中,我将该地址保存在指针“base_ptr
”中。我正在打印我在已经终止的函数“test()
”中分配的所有值,然后我使用函数“free()
”释放基地址。
我对此有几个问题。
这种释放分配内存的方式是否会产生内存泄漏的风险,这是一个好的做法吗?
通过
function end
或return
释放动态分配的内存是否与“free()
”功能相同?
如果函数“
test()
”占用(和初始化)的内存由于执行结束而被释放,那么以代码示例中的方式访问它的地址是否危险?
但是在函数“main()”中,我将该地址保存在 指针“base_ptr”。我正在打印我分配的所有值 已经终止的函数“test()”,然后我将释放 base 地址,使用函数“free()”。
从函数返回不会释放通过
malloc
系列函数分配的内存。这些内存块的生命周期与程序相同,除非你自己free
它们。在您的函数中,您不返回本地指针,仅返回对已分配内存的引用,并且此引用存储在该本地指针中。
自动存储持续时间对象的生命周期与封闭范围相同,当您离开该范围时它们将停止存在
例子:
int *foo(void)
{
int a[10];
return a; //returning pointer to the object which lifetime will end when
//function returns. If you use this returned value
//it will invoke undefined behaviour
}
正在通过函数结束释放动态分配的内存或返回 与“free()”函数相同?
不,您需要通过调用
free
函数自行释放它。
这种释放分配内存的方式是否会产生内存泄漏的风险, 这是一个好习惯吗?
不,使用
free
没有风险,而且是非常好的做法
如果函数“test()”占用(并初始化)的内存是 由于它的执行结束而被释放,访问它并不危险 像代码示例中那样以这种方式处理地址?
当您从函数返回时,此内存不会被释放,并且在您自己“释放”它之前一直有效。
现代操作系统在程序终止时释放动态分配的内存,但
free
它们是一个好习惯。
这是释放动态分配内存的好习惯吗?
是的。这是很好的做法。
代码检查了内存。 完成后放好 .
“由于执行结束而被释放”是一个糟糕的借口。将代码移植到不依赖它的更大任务更容易。
test()
应该清楚地记录它正在返回分配的内存,以后需要 free()
.
这些并没有改变上面的答案,但是 OP 示例代码中的问题掩盖了其他问题。
代码确实有其他薄弱或不良的做法:
缺乏错误检查
如果
malloc()
成功,更好的代码测试。
不需要演员
不需要转换
malloc()
的返回值。
没有检查
scanf()
的返回值。
更好的代码检查返回值。
引用对象的大小,而不是类型
在申报时分配
// char *local_ptr = NULL;
// local_ptr = (char *)malloc(5*sizeof(char));
char *local_ptr = malloc(sizeof local_ptr[0] * 5);
迂腐:使用匹配说明符
%hhi
匹配 signed char *
。它可能会失败char *
.
空间是多余的
scanf("%hhi",...
的表现与 scanf(" %hhi",...
一样,因为 %hhi
跳过前导空白。
是的,虽然大多数现代操作系统会在程序终止时释放内存,但这并不是代码内存泄漏的借口。
还要注意
malloc()
和family的返回值不需要强制转换。这些函数返回隐式转换为任何其他指针类型的通用指针类型 (void *
)。因此,它是多余的,只会使代码混乱。
#if 0
char *local_ptr = NULL;
local_ptr = (char *)malloc(5*sizeof(char));
#else
char *local_ptr = malloc (5);
if (!local_ptr) {
complain();
}
#endif
我们不需要
sizeof(char)
,因为它被标准定义为1并且首先声明和初始化指向NULL
的指针没有意义,只是立即用malloc()
的返回覆盖它。