【问题标题】:Freed pointer reallocaing itself?释放指针重新分配自身?
【发布时间】:2015-12-20 20:44:53
【问题描述】:

当我动态分配一个结构,然后尝试释放它时,它似乎重新分配它。

typedef struct OBJ_T
{
   int param1, param2;
} OBJ;

OJB* Construct(int par1, int par2)
{
   OBJ* x = malloc(sizeof(OBJ));
   x->param1 = par1;
   x->param2 = par2;
   return x;
}

void freeup(OBJ *x)
{
   printf("x pointer -> %d ", x);
   free(x);
   x=NULL;
   printf("\nx pointer -> %d\n", x);
}

int main()
{
   OBJ foo = *Construct(10, 20);
   freeup(&foo);
   freeup(&foo);
   return 0;
}

结果是:

x pointer -> 2752216
x pointer -> 0
x pointer -> 2752216
x pointer -> 0

所以在释放并清空指针之后,如果我再次检查它,它会恢复到原来的状态。那是问题吗?或者它是免费的,我再也不用担心了?

【问题讨论】:

  • 指针滥用组想和你谈谈。严肃地说,您正在丢失 OBJ foo = *Construct(10,20) 行中的原始指针。
  • 您似乎有 Java 或 Delphi 背景?所以有一些关于指针的知识。
  • 无法在堆栈上分配的内存上调用free()freeup(&foo);
  • @alk 但似乎可能,很明显:你不应该这样做。你能描述一下这里发生了什么吗? UB?
  • @Wolf:“这似乎是可能的。”是 C 语言中的一个非常弱论点。

标签: c struct structure dynamic-allocation


【解决方案1】:

首先,这一行是在堆栈上分配foo,然后将动态分配的结构复制到该位置:

OBJ foo = *Construct(10, 20);

当然,你不应该释放它。正确的大小写是:

OBJ* foo = Construct(10, 20);
. . .
freeup(foo);

其次,如果要清除freeup中的指针,则将参数类型改为pointer-to-pointer:

void freeup(OBJ** x)
{
   free(*x);
   *x=NULL;
}

...在这种情况下,您应该将freeup 调用更改为freeup(&foo);

最后,foo 似乎在您的代码中被重新分配,但它不能被释放或分配,它是一个堆栈变量。所以指向foo的指针在函数内部总是相同的。

【讨论】:

  • 您正在双重释放分配的内存,这是一个问题。您还将指针的值传递了两次(您已将 &foo 的按值传递副本设置为 0,这不会更改 &foo)。
  • 对。 ...但它没有回答最初的问题。也许还建议一个OBJ **x 参数。 (或者最好不要?)
  • @Wolf 我的评论现在更清楚了吗?我完全忘记了按回车键并没有给我一个新行,而是提交了评论。 ://
  • ... 并像这样调用freeup(OBJ **) freeup(&foo);
  • @alk 我添加了一行来完成这个选项
【解决方案2】:

你的指针在行中丢失

OBJ foo = *Construct(10, 20);

您获取Construct 返回的指针指向的结构OBJ,将其值复制到foo,然后丢弃指针。 之后,因为没有指针,所以无法释放由Constructor 分配的实际struct OBJ

那么你的freeup 调用是错误的,因为你试图释放foo,而不是原来的。

正确的方法是继续使用指针,所以

OBJ *foo = Construct(10, 20);
...
freeup(foo);

或者根本不使用指针,只在Construct 中返回OBJ,而不是OBJ*。这样,就不用担心释放任何东西了。

【讨论】:

  • 我现在明白了,我不应该使用指针,因为我并不真正需要。谢谢你。
【解决方案3】:

您的代码中有多个问题:

  1. 失去对原始 malloc 指针的引用
  2. 试图释放堆栈上的对象
  3. 将 0 分配给指针的副本(传递给 freeup)

(1) OBJ foo = *Construct(10, 20); 行没有将分配的 OBJ 的指针分配给 foo,而是将 OBJ 的值复制到堆栈中,复制到名为 foo 的变量中,这会导致您丢失引用到分配的对象(并导致内存泄漏)。

更好的方法是返回指针本身,更清晰,不会导致你丢失引用,效率更高:

OBJ *foo = Construct(10, 20);

现在 foo 是指向对象的指针,而不是对象本身。

(2) 派生自 (1),现在我们使用 foo 作为指向 malloc 对象的指针,我们可以对其使用 free。

(3) 从被调用者分配给参数不会改变调用者站点中的值。这被称为pass-by-value,因为只有参数值的副本被传递给被调用者。那我们换个freeup

void freeup(OBJ **x)
{
   printf("x pointer -> %d ", *x);
   free(*x);
   *x=NULL;
   printf("\nx pointer -> %d\n", *x);
}

这样,调用者站点的指针值就会改变。


请注意,我省略了 NULL 检查等以使代码更清晰,但它们绝对应该存在。

【讨论】:

    【解决方案4】:
     OBJ foo = *Construct(10, 20);
    

    因此,您丢失了指向由 malloc 分配的块的指针。所以freeing 内存没有被malloc 分配或者类似的原因导致程序出错。

    这个我真的不明白(一般来说 - 也不应该用指针来完成)-

    freeup(&foo);              // just one call is enough 
    freeup(&foo);              // Why twice ?  
    

    还有这个-

      void freeup(OBJ *x)
    {
        printf("x pointer -> %d ", x);
        free(x);
        x=NULL;
        printf("\nx pointer -> %d\n", x);          // should not be done in any case after assigning pointer to NULL
    }
    

    你可以这样做-

      void freeup(OBJ **x)
       {
            printf("x pointer -> %d ", *x);
            free(*x);
           *x = NULL;
      }
    

    以与freeup(&foo);相同的方式调用它

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-25
      • 2018-09-30
      • 2019-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多