【问题标题】:C memory leak even after free'ing pointer to struct即使在释放指向结构的指针之后,C 内存泄漏
【发布时间】:2023-03-23 11:35:02
【问题描述】:

我有一个二次多项式系数的结构。我声明了一个这种结构类型的变量,我读取了系数的值,然后我创建并初始化了一个指向这个结构的指针。然后,我使用我的结构和指向结构变量的指针显示系数的值。最后,我将指向 struct 的指针设置为 NULL 并释放它。

但是,valgrind 检测到内存泄漏,我终其一生都无法理解原因。你能帮我理解吗?

valgrind ./polynome --leak-check=full 
==11046== Memcheck, a memory error detector
==11046== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==11046== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==11046== Command: ./polynome --leak-check=full
==11046== 
2 3 4
pCoeff: a = 2.000000, b = 3.000000, c = 4.000000
 coeff: a = 2.000000, b = 3.000000, c = 4.000000
==11046== 
==11046== HEAP SUMMARY:
==11046==     in use at exit: 24 bytes in 1 blocks
==11046==   total heap usage: 1 allocs, 0 frees, 24 bytes allocated
==11046== 
==11046== LEAK SUMMARY:
==11046==    definitely lost: 24 bytes in 1 blocks
==11046==    indirectly lost: 0 bytes in 0 blocks
==11046==      possibly lost: 0 bytes in 0 blocks
==11046==    still reachable: 0 bytes in 0 blocks
==11046==         suppressed: 0 bytes in 0 blocks
==11046== Rerun with --leak-check=full to see details of leaked memory
==11046== 
==11046== For counts of detected and suppressed errors, rerun with: -v
==11046== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

这是我的 C 程序:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
   double a;
   double b;
   double c;
} Coefficient;

int main() {
    Coefficient *pCoeff = NULL;
    Coefficient coeff;

    scanf("%lf %lf %lf", &coeff.a, &coeff.b, &coeff.c);

    pCoeff = (Coefficient *)malloc(sizeof(Coefficient));
    if (pCoeff == NULL) {
        fprintf(stderr, "Memory allocation error.\n");
        exit(1);
    }   

    pCoeff = &coeff;

    printf("pCoeff: a = %lf, b = %lf, c = %lf\n", pCoeff->a, pCoeff->b, pCoeff->c);
    printf(" coeff: a = %lf, b = %lf, c = %lf\n", coeff.a, coeff.b, coeff.c);

    pCoeff = NULL; 
    free(pCoeff); 

    return 0;
}

【问题讨论】:

  • 你必须先释放指针。然后将其设置为 NULL。
  • @MartinZabel:如果我在释放之前没有将指针设置为 NULL,则会出现双重释放或损坏错误(因为它仍然指向 coeff 变量的地址)。跨度>
  • @user3121023:是的,我只是想在使用结构的动态分配中测试 int var = 3; int *p = &amp;var; 的等价物,我对为什么会出现内存泄漏感到困惑。还是你的意思是说我不应该那样做?
  • 我认为我应该使用 &coeff=NULL;免费(pCoeff);
  • @ganchito55:不,它不能工作,因为你不能在分配的左侧有地址运算符。

标签: c pointers struct memory-leaks


【解决方案1】:

内存泄漏 1

您的第一个问题在于以下语句,它与代码所做的不对应:

然后我创建并初始化一个指向这个结构的指针

请记住,变量pCoeff 是一个指针,即它存储一个地址

排队

pCoeff = (Coefficient *)malloc(sizeof(Coefficient));

您将新动态分配结构的地址存储在pCoeff 中。接下来,在行中

pCoeff = &amp;coeff;

您将静态分配结构coeff地址 存储在pCoeff(覆盖先前的值)中。这样做会丢失对动态分配内存的唯一引用,从而导致内存泄漏。

实际复制结构的的正确解决方案是使用memcpy 函数,或者

*pCoeff = coeff;

内存泄漏 2

第二个问题在于释放过程中的语句顺序。

排队

pCoeff = NULL; 

您将 NULL 地址存储在pCoeff(覆盖之前的值)中。这样做,您将再次丢失唯一的引用并导致内存泄漏。

然后,排队

free(pCoeff);

您使用存储在pCoeff 中的值调用free。由于现在的值为NULL,因此该函数不执行任何操作。

正确的释放顺序应该是两个语句的顺序相反:

pCoeff = NULL; 
free(pCoeff); 

不必要的代码

变量coeff 似乎是多余的,因为您动态分配相同类型并复制值。可以先分配,然后直接读取pCoeff指向的内存。

例如:

Coefficient *pCoeff = NULL;
pCoeff = (Coefficient *)malloc(sizeof(Coefficient));
if (NULL == pCoeff) {
    fprintf(stderr, "Memory allocation error.\n");
    exit(1);
}   

scanf("%lf %lf %lf", &pCoeff->a, &pCoeff->b, &pCoeff->c);
/* TODO: Check the return value of scanf. */

printf("pCoeff: a = %lf, b = %lf, c = %lf\n", pCoeff->a, pCoeff->b, pCoeff->c);

...

【讨论】:

  • 谢谢。现在很清楚了。是的,coeff 是多余的,我只是在测试堆栈上的结构与动态分配。
【解决方案2】:

你的问题是这些代码行放在一起没有意义:

Coefficient *pCoeff = NULL;
Coefficient coeff;

// this points pCoeff at a malloc()'d structure
pCoeff = (Coefficient *)malloc(sizeof(Coefficient));

// this points pCoeff at the structure on the stack - and
// leaks the one malloc()`d above
pCoeff = &coeff;

pCoeff = NULL; 
// free() of a NULL pointer does nothing
free(pCoeff); 

malloc() 然后 free() Coefficient 结构,或者使用堆栈上的结构。你不需要两者都做。

【讨论】:

  • 是的,你是对的,这没有任何意义。 :) 我只是想了解在堆栈上使用结构与使用动态分配的不足之处。感谢您的回答和我收到的其他人,我现在明白了。
猜你喜欢
  • 2014-09-25
  • 1970-01-01
  • 2017-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-14
  • 1970-01-01
相关资源
最近更新 更多