首页 文章

在函数返回后,函数中分配的内存是否仍然保持分配状态?

提问于
浏览
12

对于以下代码: (1) "main"调用函数"f1" . (2) 函数"f1"做了一些数字处理;使用malloc创建一个"char"数组,然后将数组的指针返回给main(不分配-freeing-数组) .

我有3个与案例有关的问题: (1) 我假设,虽然函数"f1"已经终止,但分配的char数组仍然保持分配状态,直到主程序完全终止 . 也就是说,分配的内存仍然属于主内存,没有其他进程可以从外部访问(我的意思是,干扰)它 . 我对吗? (2) 我是否必须在程序终止之前释放阵列(在"f1"中分配)(或者在主程序终止后立即释放)? (3) 如果第二个问题的答案是"yes"那么你如何释放另一个函数中分配的数组?

注意:我想保持在纯粹的c的范围内,而不是溢出到c .

char *f1 (...) {
    ...
    ...
    char *fTmp = malloc (length1 * sizeof (char));
    char *fData = malloc (length2 * sizeof (char));
    ...
    ...
    free (fTmp);
    return (fData);
}

int main () {
    char *fData = f1 (...);
    ...
    return (0);
}

7 回答

  • 1

    我假设,虽然函数“f1”已经终止,但分配的char数组仍然保持分配状态,直到主程序完全终止 .

    真正 . 动态分配的内存与函数无关,它属于进程 .

    也就是说,分配的内存仍然属于主内存,没有其他进程可以从外部访问它 . 我对吗?

    内存不属于 main() (用作函数),而是处理自身(其中 main() 只是入口点) . 在具有内存保护的系统中(每个进程与其他进程隔离),无法从外部访问 . 但是,您可以以特定于系统的方式分配它,以跨进程共享内存 .

    在程序终止之前,我是否必须释放阵列(在“f1”中分配)(或者在主程序终止后立即释放)?

    是 . 未分配的内存 - in most systems - 在进程终止时由操作系统自动释放,但这取决于系统 . IMO甚至在操作系统执行时你应该总是解除分配,使用这种自动释放作为红旗(我忘记了解除分配,这是一个错误吗?我错过了什么?) . 此外,如果 f1 被调用1000次,那么每次快速吃掉所有可用内存都会泄漏内存 . 想想服务器中的进程,它可能(并且应该)启动并运行多年 .

    如果第二个问题的答案是“是”,那么如何释放在另一个函数中分配的数组?

    它's nice when who allocates memory also frees it. If it'不可能,然后调用者将负责这样的内存 . 例如, strdup() 的作用 . 在这种情况下,被调用的函数必须返回(以某种方式)指向已分配内存的指针(或可由另一个专用函数使用的句柄/令牌) . 例如:

    char* pBuffer = f1();
    // Use it
    free(pBuffer);
    

    请注意,如果要隐藏此类内部指针,有许多技术 . 您可以使用标记(例如,整数,字典中的键), typedef 或不透明类型 .

  • 16
    • 是的,分配有 malloc() 的内存一直保留,直到被释放 . 函数如何才能将可变大小的数据返回给调用者?

    • 程序退出时,将释放分配有 malloc() 的所有内存 . 但是,在程序终止之前保留大量不需要的内存通常不是一个好主意,因为它会影响性能,或者系统可能耗尽虚拟内存 . 对于长时间运行的程序,这可能是一个特别关注的问题,它们的内存使用有时会持续增长,直到它们使用所有可用的虚拟内存 .

    • 您在函数返回的指针上调用 free() . 所以在你的情况下, main() 在使用数组完成后可以做 free(fData) .

    这应该都包含在任何C编程类或教科书中 .

  • 6

    malloc 在堆上分配内存,因此这个内存保持分配状态,直到它被 free 函数释放或程序终止成功 .
    在您的情况下,您在 f1 中释放了 ftemp ,因此在函数终止后它不再存在 . fdata 仍然在堆上,当您返回指向该分配位置的指针时, main 可以访问它 .

    一旦 main 成功终止, fdata 指向的内存将被释放 .

    所以,只要你不再需要它就可以释放内存 . 在程序结束时释放块是没有意义的,因为全部当进程终止时(考虑到现代操作系统),程序的空间将返回给系统 .

  • 2
    • 是的,它还在堆里 . 但是,您对流程的概念感到困惑 . 除非你创建另一个进程(在* nix上使用 fork ),否则它仍然是相同的进程 .

    • 在不使用时释放内存是个好习惯 . 但是如果程序正常终止,系统将释放分配的内存 .

    • 喜欢这个:

    int main () {
        char *fData = f1 (...);
        //...
        free(fData);
        //...
    }
    
  • 1

    使用 malloc 将在堆上分配内存,直到它 free 它 .

    这意味着您需要确保每个malloc都有相应的免费,也并不意味着没有其他进程无法访问您的数据 . 它只是一个地址的值 .

    在你的主要你必须 free(fData) 以避免内存泄漏 .

    To sum up then:

    1)你的第一个假设是正确的,第二个和第三个假设是正确的 . 它将保持分配状态,但它不是主要的本地,并且在它终止时不受该进程的约束 .

    2)是的,你必须释放它

    3)使用从函数中获得的指针 . 如果没有从函数返回指向已分配数据的指针,请确保函数 free s .

  • 1

    在C中可以使用两种基本类型的内存 . 两种类型是堆栈和堆 . 通常,在函数中创建的变量将在堆栈上分配,并在函数返回时释放 . 堆中分配的内存将保持不变,您有义务在程序中管理该分配 . 堆中的内存将保持分配状态,直到您使用引用数据块的指针(内存地址)释放为止 .

    对它们进行一点阅读将有助于您理解 . 我要指出你有两个fData实例,每个实例都有自己的范围 . 两个指针都指向您分配的内存:

    char *fData = malloc (length2 * sizeof (char));
    

    ..即使它们在代码执行时传入和传出范围 .

  • 1

    如果你没有使用,最终会累积 - 如果你用许多其他指针完成此操作 - 你的程序可能会耗尽内存 . 在使用 free 函数释放内存块之后,我还建议将 NULL 分配给指针,因为这可以防止悬空指针,即使你已经释放了一个指针,如果你尝试访问它,你可能会得到未定义的行为,而访问对 NULL 指针的操作导致崩溃,因此您可以轻松地跟踪问题

相关问题