这是否是释放动态分配内存的良好实跃实践?

huangapple go评论63阅读模式
英文:

Is this a good practice of freeing dynamically allocated memory or it's not?

问题

I wrote the following code sample:

#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;
}

So, I know that once allocated by "malloc()" or "calloc()", I have to free the allocated memory using the "free()" function.

In the code sample I'm showing, I'm doing the allocation in the function "test", which returns a pointer. The pointer returned carries the base address of the allocated array. Inside the function "test()" there is no use of the function "free()", since reaching the return operator, the program leaves the function, which leads to freeing the memory as from the function itself, so from all of its local variables, including the pointer, which holds the base address.

But inside the function "main()", I'm keeping that address in the pointer "base_ptr". I'm printing all the values, which I assigned in the already terminated function "test()", then I'm freeing the base address, using the function "free()".

I have a couple of questions regarding this.

Does this way of freeing allocated memory create a risk of memory leak, is it good practice at all?

Is freeing dynamically allocated memory via function end or return the same as "free()" function?

If the memory, occupied (and initialized) by the function "test()" is freed due to its execution end, isn't it dangerous to access its addresses in such a manner, as in the code sample?

(Note: I've made minor adjustments for readability, but the content remains the same.)

英文:

I wrote the following code sample:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

char *test(void);

int main()
{
    char *base_ptr = NULL;

    base_ptr = test();

    for (char i = 0; i &lt; 5; i++)
    {
        printf(&quot;base_ptr[%hhi] = %hhi\n&quot;, 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 &lt; 5; i++)
    {
        scanf(&quot; %hhi&quot;, &amp;local_ptr[i]);
    }

    return local_ptr;
}

So, I know that once allocated by "malloc()" or "calloc()", I have to free the allocated memory using the "free()" function.

In the code sample I'm showing, I'm doing the allocation in the function "test", which returns a pointer. The pointer returned carries the base address of the allocated array. Inside the function "test()" there is no use of the function "free()", since reaching the return operator, the program leaves the function, which leads to freeing the memory as from the function itself, so from all of it's local variables, including the pointer, which holds the base address.

But inside the function "main()", I'm keeping that address in the pointer "base_ptr". I'm printing all the values, which I assigned in the already terminated function "test()", then I'm freeing the base adddress, using the function "free()".

I have a couple of questions regarding this.

Does this way of freeing alocated memory creates risk of memory leak, is it a good practice at all?

Is freeing dynamically allocated memory via function end or return the same as "free()" function?

If the memory, occupied (and initialized) by the function "test()" is freed due to it's execution end, isn't dangerous to access it's addresses in such maner, as in the code sample?

答案1

得分: 3

> 这是释放动态分配内存的良好做法吗?还是不是?

是的。这是良好的做法。

代码检查了内存。完成后,请将其放在一边。

"由于执行结束而被释放"是一个不好的借口。更容易将代码移植到不依赖于它的更大任务中。

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);

学究式:使用匹配的说明符

%hhisigned char * 匹配。对于 char * 可能会失败。

空格是多余的

scanf("%hhi", ... 的性能与 scanf(" %hhi", ... 相似,因为 %hhi 跳过前导空白。

英文:

> Is this a good practice of freeing dynamically allocated memory or it's not?

Yes. It is good practice.

Code checked out memory. Put it away when done
.

"freed due to it's execution end" is a poor excuse. It is easier to port code to larger tasks that do not rely on that.

test() should clearly document that it is returning allocated memory that later needs a free().


These do not change the above answer, yet the troubles in OP's sample code belie other issues.

Code does have other weak or poor practices:

Lack of error check

Better code tests if malloc() succeeded.

Cast not needed

Castling the return value of malloc() is not needed.

Failure to check the return value of scanf().

Better code checks the return value.

Size to the referenced object, not type

Assign at declaration

//  char *local_ptr = NULL;
// local_ptr = (char *)malloc(5*sizeof(char));

char *local_ptr = malloc(sizeof local_ptr[0] * 5);

Pedantic: Use matchings specifier

%hhi matches a signed char *. It might fail for a char *.

Space is redundant

scanf(&quot;%hhi&quot;,... performs like scanf(&quot; %hhi&quot;,... as %hhi skips leading white-space.

答案2

得分: 2

> 但在函数"main()"内部,我将那个地址保留在指针"base_ptr"中。我打印了在已终止的函数"test()"中分配的所有值,然后使用函数"free()"释放了基地址。

从函数返回不会释放通过malloc系列函数分配的内存。这些内存块的生命周期与程序相同,除非你自己使用free释放它们。在你的函数中,你没有返回一个局部指针,只返回了分配的内存的引用,这个引用存储在那个局部指针中。

自动存储期对象的生命周期与包含作用域相同,当你离开这个作用域时,它们将停止存在。

示例:

int *foo(void)
{
    int a[10];
    return a;  //返回指向对象的指针,该对象的生命周期将在函数返回时结束。
               //如果你使用返回的值,将会导致未定义行为。
}

> 释放动态分配的内存通过函数结束或返回与"free()"函数相同吗?

不,你需要自己调用free函数来释放它。

> 通过这种方式释放分配的内存会导致内存泄漏的风险吗?这是一个好的做法吗?

不,使用free没有内存泄漏的风险,这是一个非常好的做法。

> 如果函数"test()"占用的内存(并初始化)在执行结束时被释放,以这种方式访问它的地址是否危险,就像在代码示例中一样?

当你从函数返回时,这段内存并未被释放,它在你自己调用free之前是有效的。

现代操作系统会在程序终止时释放动态分配的内存,但最好还是使用free来做这件事。

英文:

> But inside the function "main()", I'm keeping that address in the
> pointer "base_ptr". I'm printing all the values, which I assigned in
> the already terminated function "test()", then I'm freeing the base
> adddress, using the function "free()".

Returning from the function does not free the memory allocated via malloc family function. Those memory blocks have a lifetime the same as the program unless you free them yourself. In your function, you do not return a local pointer, only the reference to the allocated memory and this reference is stored in that local pointer.

Automatic storage duration objects instead have a lifetime same as enclosing scope and they stop to exist when you leave this scope

Example:

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
}

> Is freeing dynamically allocated memory via function end or return the
> same as "free()" function?

No, you need to free it yourself by calling free function.

> Does this way of freeing alocated memory creates risk of memory leak,
> is it a good practice at all?

No, there is no risk of using free, and it is a very good practice

> If the memory, occupied (and initialized) by the function "test()" is
> freed due to it's execution end, isn't dangerous to access it's
> addresses in such maner, as in the code sample?

This memory is not freed when you return from the function and it is valid until you 'free' it yourself.

Modern operating systems free the dynamically allocated memory on program termination, but it a good practice to free them.

答案3

得分: 1

Yes, although most modern operating systems will free the memory on program termination, that isn't an excuse for having memory leaks all over one's code.

Also note that the return value of malloc() and family need not be cast. These functions return a generic pointer type (void *) that is implicitly converted to any other pointer type. As such, it is redundant and only serves to clutter one's code.

We do not need sizeof(char) as it's defined by the standard to be 1, and there is no point in first declaring and initializing the pointer to NULL, only to overwrite it with the return of malloc() immediately.

英文:

Yes, although most modern operating systems will free the memory on program termination, that isn't an excuse for having memory leaks all over one's code.

Also note that the return value of malloc() and family need not be cast. These functions return a generic pointer type (void *) that is implicitly converted to any other pointer type. As such, it is redundant and only serves to clutter one's code.

#if 0
    char *local_ptr = NULL;
    local_ptr = (char *)malloc(5*sizeof(char));
#else
    char *local_ptr = malloc (5);
    if (!local_ptr) {
        complain();
    }
#endif

We do not need sizeof(char) as it's defined by the standard to be 1 and there is no point in first declaring and initialising the pointer to NULL, only to overwrite it with the return of malloc() immediately.

huangapple
  • 本文由 发表于 2023年5月14日 06:14:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76245084.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定