【问题标题】:Freeing dynamically allocated int that needs to be returned but cannot be freed in main in c释放动态分配的 int 需要返回但不能在 c 中的 main 中释放
【发布时间】:2017-03-03 15:01:13
【问题描述】:

正如我的长标题所说:我试图在 c 中返回一个已动态分配的指针,我知道,我必须释放它,但我不知道如何自己,我的搜索表明它只能在 main 中被释放,但我不能让用户来释放 int。

我的代码现在看起来像这样,

int *toInt(BigInt *p)
{
    int *integer = NULL;

    integer = calloc(1, sizeof(int));

    // do some stuff here to make integer become an int from a passed
    // struct array of integers

    return integer;
}

我尝试只创建一个临时变量并查看其整数,然后释放整数并返回临时变量,但这没有奏效。必须有一种方法可以在不释放 main 的情况下做到这一点?

【问题讨论】:

  • 我不知道你搜索了什么,但你几乎可以在任何地方释放分配的内存,而不仅仅是在主目录中。
  • 如果您将 maloc() / calloc() 的结果作为返回值传递,您通常无法知道调用者对该指针做了什么,因此您应该将其留给调用者释放它,如果它不再需要
  • 为什么main中不能是freed?如果有人拿着枪站在你身后,请眨眼。否则,您应该查阅一本关于指针和动态内存分配的好 C 书。我不明白你的问题是什么。
  • @Olaf 因为那是导致内存泄漏的糟糕设计?
  • @Lundin:我们没有看到完整的代码。很可能程序中只有两个函数:这个和main,并且只有一个模块。除非我有完整的图片(或者至少是一张足够宽的图片),否则我会小心地称某些东西为“糟糕”。我们首先需要一个minimal reproducible example。 (哦,“不能”与“不应该”不一样)。

标签: c memory-leaks free


【解决方案1】:

在程序设计方面,您应该始终让进行分配的“模块”(翻译单元)负责释放内存。期望其他模块或调用者 free() 内存确实是糟糕的设计。

不幸的是,C 没有构造函数/析构函数(也没有“RAII”),所以这必须通过单独的函数调用来处理。从概念上讲,您应该像这样设计程序:

#include "my_type.h"

int main()
{
  my_type* mt = my_type_alloc();
  ...
  my_type_free(mt);
}

至于您的具体情况,不需要动态分配。只需将分配留给调用者,并使用专用的错误类型来报告错误:

err_t toInt (const BigInt* p, int* integer)
{
   if(bad_things())
     return ERROR;

   *integer = p->stuff();

   return OK;
}

err_t 是一些自定义错误处理类型(可能是枚举)。

【讨论】:

  • 我了解这是一种更好的方法,但我受到以下特定限制:将 p 表示的整数转换为动态分配的 int,并返回指向该值的指针。如果 p 为 NULL,则只需返回 NULL。如果p表示的整数超过limits.h中定义的最大int值,返回NULL。
【解决方案2】:

正如@unwind 已经观察到的那样,您的特定代码不会从动态分配中获得任何有用的信息。只要避免它,您就可以为自己省去很多麻烦。

从更一般的意义上说,您应该想象每个分配的内存块都与一个隐含的释放义务相关联。该义务没有物理或电子表示,但您可以将其想象为在任何给定时间关联的虚拟提示,在分配的生命周期内最多有一个指向空间的指针副本。您可以随意在指针值的副本之间转移义务。如果具有义务的指针值因超出范围或被修改而丢失,那么您至少在原则上存在泄漏;如果您通过当时没有释放义务的指针副本释放空间,那么您有一个(可能是虚拟的)双重释放。

我知道我必须释放它,但我不知道如何释放它

应该假设分配内存并返回指向它的指针副本而不制作任何其他副本的函数(例如您的示例)将释放义务与返回的指针值相关联。它本身不能释放分配的空间,因为在函数返回后该空间必须保持分配状态(否则返回的指针比无用更糟糕)。如果释放的义务没有转移到返回的指针上,那么当函数的局部变量在其末尾超出范围时就会发生(虚拟)内存泄漏,从而不会留下有义务释放的指针的现存副本。

我不能让用户来释放 int。

如果你的意思是你不能把它留给调用者,那你就错了。当然,您可以将其留给调用者。如果实际上该函数分配空间并按照您的描述返回一个指向它的指针,那么它必须将释放的义务连同返回的指向分配空间的指针副本一起转移给调用者。这正是calloc() 函数首先所做的。其他函数做的类似,比如POSIX的strdup()

由于没有物理或电子形式的释放义务,因此您的函数必须记录调用者承担的任何此类义务。

【讨论】:

  • 约翰的好答案。
【解决方案3】:

别再把它当成一个指针了,不需要一个int

直接返回,自动分配不会有内存管理问题:

int toInt(const BigInt *p)
{
  int x;
  x = do some stuff;
  return x;
}

调用者可以这样做

const int my_x = toInt(myBigInt);

my_x 会在超出范围时被自动清除。

【讨论】:

  • 此函数返回指针而不是 int 的唯一原因是,在 p 不能表示为 int 的情况下,我可以返回 NULL 来表示失败。就像要转换的数组大于 2 ^ 31 - 1
  • @GrahamChapman 这仍然不能证明你分配一个 int 是合理的。如果您想检查限制,为什么不与limits.h 中的INT_MAXINT_MIN 进行比较?
  • 使用 malloc(sizeof(int)) 代替 calloc 会更合适吗?我所知道的是我必须将 p 表示的整数转换为动态分配的 int 并返回一个指向该值的指针。
  • @GrahamChapman,如果确实使用指针的唯一原因是提供通过返回NULL 来传达错误的机会,那么也许您应该考虑通过不同的方式发出错误信号。例如,让函数返回一个成功代码,并让它通过输出参数提供实际转换后的值。或者返回一个包含成功代码和转换值的结构,后者在失败的情况下没有意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-22
  • 2023-03-03
  • 2021-06-02
  • 2012-07-12
  • 2010-12-05
相关资源
最近更新 更多