【问题标题】:How to free a char* that is being returned from another function?如何释放从另一个函数返回的 char*?
【发布时间】:2014-05-08 11:18:49
【问题描述】:

假设我们有以下场景。

char* halfString(char* input) {
    char* output = malloc(strlen(input));
    int i = 0;
    for(i = 0; i < strlen(input); i++)
        output[i] == input[i];
    output[i] = '\0';
    return output;
}

int main() {
    char* input = "Hello";
    char* output = halfString(input);
    printf("%s\n",output);
    free(output);
} 

调用“free(output)”是否会释放 main 本地的 char* 输出的内存并释放 halfString() 本地的 char* 输出的内存?或者 halfString() 本地的 char* 输出是否仍然存在内存泄漏?

感谢任何帮助。

【问题讨论】:

  • 您可能还想实际分配足够的空间。您目前是一个 char 短。 strlen(),您应该只调用一次并保存到本地以用于您的枚举,返回长度没有终止符。你的数学应该使用strlen(input)+1

标签: c memory-leaks malloc free


【解决方案1】:

您似乎混淆了两个相关的项目:缓冲区和指针。缓冲区是一块内存,在您的问题的上下文中,它是使用malloc() 分配的。指针是相关的,因为它指向一个缓冲区,但它不是缓冲区本身。

在您的halfString() 函数中,您分配一个缓冲区,并将该缓冲区的地址(指向)存储在本地output 中。然后将其返回给调用者main(),巧合的是指向同一个缓冲区的同名变量。

现在,在main() 中,当您free(output); 时,您不是在释放指针,而是在释放指针指向的缓冲区。分配缓冲区的位置无关紧要,重要的是分配了缓冲区(并且尚未释放)。在这个调用之后,你的 main 函数的 output 变量仍然存在,并且它仍然有一个曾经是有效缓冲区的地址——但是这个缓冲区当然不能被使用,因为它不再有效。

现在关于您的问题“是否存在内存泄漏?” -- 你已经 malloc 了一个缓冲区,然后你释放了同一个缓冲区,所以没有链接。始终正确地将 malloc 与 free 配对,这样您的状态就会很好。

【讨论】:

    【解决方案2】:

    代码大部分是正确的,因为malloc() 将内存放在堆上,free() 释放它。从哪个函数调用它们并不重要。

    也就是说,有一个重要的错误:

    char* output = malloc(strlen(input) + 1); // Don't forget +1
    

    strlen() 函数返回字符串中的字符数,不包括终止符。

    这些错误通常可以通过使用 Mudflap(如果使用 GCC,使用 -fmudflap 编译)和 Valgrind 等特定工具自动捕获。

    算法复杂度

    代码的算法复杂性存在问题,启用优化后,使用好的编译器可能会消失。

    for(i = 0; i < strlen(input); i++)
    

    这将调用strlen(),即O(N),它会调用strlen() O(N) 次,给出O(N2) 的渐近性能。我们可以做得更好,这里有两个修复:

    // Version 1
    size_t i, n = strlen(input);
    for (i = 0; i < n; i++)
        ...
    
    // Version 2
    size_t i;
    for (i = 0; input[i] != '\0'; i++)
        ...
    

    【讨论】:

      【解决方案3】:

      没有内存泄漏。系统知道有多少内存与指针相关联,并且由于您无法释放使用 malloc 分配的内存块的一部分,因此它将全部释放。

      【讨论】:

        【解决方案4】:

        没有内存泄漏。

        不过,您似乎对堆分配的工作原理感到困惑。这里只分配了 一个 内存块,它对于halfString()main() 都不是“本地”的。分配的块存在于堆中,并且不局限于特定的代码块。

        malloc() 返回一个指向它的指针。然后将该指针返回到main(),但指针的值仍然相同:它指向内存中的相同地址,相同的堆块。 main() 然后正确释放它。

        作为设计考虑,这通常不是最好的做法。一般来说,调用者不一定知道halfString()返回的指针指向一个用malloc()分配的块并且他们需要free()它。这必须非常清楚和仔细地记录下来。更好的解决方案可能是提供一个 freeHalfString() 函数来进行释放;那么从维护的角度来看,这两个函数可以放在同一个地方并同时维护,这样调用者就不需要担心缓冲区是如何分配的,或者如何释放它。

        (正如其他人指出的那样,您还存在缓冲区溢出,因为您需要分配 strlen(input) + 1 字节以包含 NULL 终止符。)

        【讨论】:

          【解决方案5】:

          此代码将正常工作(如果其他人提到的非同一个错误已修复)。 main 中的调用将释放halfString 中分配的内存。

          没有“主输出的本地内存”。 main 的本地是输出指针,它分配在堆栈上,当 main 退出时将超出范围。

          【讨论】:

            【解决方案6】:

            free() 将释放被调用函数本身分配的内存。它不是任何函数的本地函数,因为 malloc allocates memory on heap.
            您称为 local memory 的内容位于 stack 上,当函数返回时将被释放。
            那么使用malloc 完成的分配是在heap 上进行的,并且您使用的过程将释放在被调用函数中分配的内存。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-09-16
              • 1970-01-01
              • 1970-01-01
              • 2012-08-07
              • 2021-06-14
              • 1970-01-01
              • 2021-12-11
              相关资源
              最近更新 更多