【问题标题】:What happens when you call malloc on an existing variable?当您在现有变量上调用 malloc 时会发生什么?
【发布时间】:2016-09-15 21:11:31
【问题描述】:

如果一个变量过去已经被malloc'ed,如果你再次调用malloc而不是realloc会发生什么?会不会造成内存泄露?

我想知道,以便在malloc 调用传递给函数的参数之前添加检查,以避免潜在的泄漏。

void memtest(char **foo)
{
        if ( foo )
                *foo = malloc(10); // Assuming *foo was already allocated in the past.
}

我应该始终执行以下操作吗?

void memtest(char **foo)
{
        if ( foo ) {
                if ( *foo ) {
                        free(*foo);

                        *foo = NULL;
                }

                *foo = malloc(10);
        }
}

【问题讨论】:

  • 问题最好加个sn-p代码。
  • 没有“在变量上调用 malloc”这样的东西。

标签: c memory-management


【解决方案1】:

如果*foo 的指针包含指向先前分配的内存的唯一指针,则您只是泄漏了之前的内存。否则,它是完全无害的。

【讨论】:

    【解决方案2】:

    它会导致内存泄漏,因为之前分配的内存没有被任何变量引用并且您丢失了它的地址。

    对此没有具体的检查。您可以在声明时将指针设置为NULL,并在每次内存为freeed 时将其设置为NULL。然后您可以在拨打malloc之前查看if (pointer == NULL)

    使用realloc 可以避免内存泄漏问题,因为如果指针是空指针,则realloc 函数的行为与指定大小的malloc 函数类似。但如果您的指针未声明设置为NULL,则可能会导致问题。

    即:

    int *foo = NULL;
    
    void bar( void )
    {
         foo = realloc(foo, 10*sizeof(int));
    }
    

    realloc 的优点或缺点是它保留了你的记忆内容。

    我应该始终执行以下操作吗?

    void memtest(char **foo)
    {
            if ( *foo )
                    free(*foo);
    
            *foo = malloc(10);
    }
    

    不,您不应该因为free 没有将指针设置为NULL,并且如果您的指针仍然具有已经freeed 内存的值,则程序会因错误而中断。 我的意思是这样的代码很容易出错,如果你 free 指针在代码中的某处而不重新分配它。 并且您必须确保以NULL 作为初始值声明指针。

    【讨论】:

    • 我个人认为,代码的可读性更高。我的意思是,仅当您重新分配以前 mallocated 的东西并且您想保留内存内容时才使用 realloc。但是你只能在整个代码中使用realloc,并且可以单独使用。
    【解决方案3】:

    当您在现有变量上调用 malloc 时会发生什么?

    可能性很小:

    • 如果内存被之前的malloc分配成功,那么重新分配内存会导致内存泄漏。
    • 如果之前malloc 调用的内存分配失败,那么不会有内存泄漏。

    我应该始终执行以下操作吗?

    void memtest(char **foo)
    {
            if ( *foo )
                    free(*foo); 
            *foo = malloc(10);
    } 
    

    是的。通过这种方式,您可以确保没有内存泄漏。

    【讨论】:

    • free 没有设置指向NULL 的指针,那么if ( *foo ) free(*foo); 是错误的。我错过了什么?
    • @LPs; if ( *foo ) 正在检查之前对 malloc 的调用是否成功。如果不成功,malloc 必须返回NULL。因此,如果*foo 没有指向NULL,则释放分配块。请注意,*foo 在检查 *foo 后释放 NULL
    • 我的意思是,如果在代码的其他部分内存是空闲的并且没有分配这样的函数失败。
    • @LPs;我想我误解了你的评论。看,*foo = malloc(10) 将分配请求的内存并使*foo 指向已分配块的第一个块,或者它将返回NULL,它将分配给*foo。如果分配的内存已经被释放,那么最好将 NULL 分配给指向该内存的指针。
    • 是的,正是我的意思。好吧,这是代码维护的最佳实践。如果没有重新分配它的编码器空闲内存,因为它不需要重新分配它。 :)
    【解决方案4】:

    malloc 的调用无关紧要。

    问题是分配,如果有问题。在您执行x=42; 之后,之前的x 值就消失了,无论它可能多么重要。同样,如果foo 是您拥有的唯一指向某个内存的指针,如果您覆盖foo,您将无法再访问该内存。

    如果不指定要释放的内容,则不能致电 free。因此,如果您在丢失唯一指向它的指针之前没有释放内存,那么您将永远无法释放它,这就是内存泄漏的定义。

    【讨论】:

      【解决方案5】:

      没有“在变量上调用malloc”这样的东西。

      malloc 找到一些“空闲”内存,将其标记为“已使用”,并返回它刚刚找到的内存的起始地址。 free 将一些“已用”内存标记为“空闲”。

      当你跑步时

      *foo = malloc(10);
      

      会发生以下情况:

      • malloc 找到 10 字节的空闲内存。
      • malloc 将这 10 个字节标记为已使用。
      • malloc 返回它刚刚找到的 10 个字节的起始地址。
      • 您的程序查看foo 的值,这是一个地址,因为foo 是一个指针。
      • 您的程序将返回的地址 malloc 存储在存储在 foo 中的地址中。

      malloc 不在乎你的程序如何处理它返回的地址。它不关心你的程序是否将它存储在一个简单的变量、一个数组、另一个malloced 空间中,甚至将它写入文件。它甚至不关心你的程序是否忘记了地址,但你应该关心,因为如果你的程序不知道它试图释放的内存地址,它将永远无法调用free

      鉴于这些知识,您应该能够看到这段代码的作用:

      char *bar;
      bar = malloc(10);
      bar = malloc(10);
      free(bar);
      

      花点时间弄清楚,然后阅读以下内容:

       

       

      • 声明了一个名为bar 的变量。它的类型是char*
      • 程序调用malloc
      • malloc 找到 10 个空闲字节并将它们标记为已使用。
      • malloc 返回 10 个字节的起始地址。
      • 程序将地址存储在bar 中。 (bar 现在包含前 10 个字节的地址)
      • 程序调用malloc
      • malloc 找到另外 10 个空闲字节并将它们标记为已使用。
      • malloc 返回 10 个字节的起始地址。
      • 程序将地址存储在bar 中。 (bar 现在包含第二个 10 字节的地址)
      • 程序调用free并将第二个10字节的起始地址传递给它。
      • free 将后 10 个字节标记为空闲。

      这是内存泄漏。前 10 个字节永远不会被释放。我可以说他们永远不会被释放,因为程序不知道他们在什么地址。

      但是这个程序呢?

      char *bar;
      char *baz;
      bar = malloc(10);
      
      baz = bar;
      baz = malloc(10);
      

      在这里,我将malloc 称为“on”一个变量,该变量已经保存了malloced 的地址。那么这是内存泄漏吗?不是自己。程序可能仍然free第一个内存块,其地址仍然存储在baz中。

      但是,这绝对是内存泄漏:

      void func()
      {
          char *bar;
          char *baz;
          bar = malloc(10);
      
          baz = bar;
          baz = malloc(10);
      }
      

      我什至没有更改代码,但只是将它放在一个函数中,它现在是内存泄漏!哇啊啊啊?

      记住内存泄漏实际上是什么。内存泄漏是指程序分配内存但从未释放它。您无法仅通过查看 malloc 调用来判断程序是否释放了所有内存。


      至于第二部分——“我应该这样做吗?”

      ,你不应该。

      只有当传递给你的函数的地址的旧值是malloced 指针时,它才会起作用,并且如果调用者忘记了free它。

      您的建议将破坏以下任何功能:

      void func1()
      {
          char c;
          char *ptr = &c;
          memtest(&ptr); // Tries to free something that wasn't malloced!
          // ... do something with ptr ...
      }
      void func2()
      {
          char *ptr;
          memtest(&ptr); // Passes a garbage address to free!
          // ... do something with ptr ...
      }
      void func3()
      {
          char *ptr1 = malloc(5)
          char *ptr2 = ptr1;
          memtest(&ptr1);
          // ... do something with ptr1 and ptr2 ...
          free(ptr1); // Frees memory that was already freed!
      }
      

      结论:标题中的问题没有意义。而检测内存泄漏并不是这么简单。而你正在尝试做的是一个坏主意。

      【讨论】:

      • 我觉得我只是因为费心写一个长答案而自动得到了接受的答案。真的有用吗?
      • 我也是这么想的。你的辛勤工作得到了回报:)
      • 是的,接受的答案越多,写得越快……啊;)顺便说一句,答案很好。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-29
      • 1970-01-01
      • 2022-12-11
      • 2016-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多