对于以下代码: (1)“main”调用函数“f1”。 (2)功能“f1”进行一些数字处理;使用malloc创建一个“char”数组,然后将数组的指针返回给main(不分配-freeing-数组)。
我有3个与案件有关的问题: (1)我假设,虽然函数“f1”已经终止,但分配的char数组仍然保持分配状态,直到主程序完全终止。也就是说,分配的内存仍然属于主内存,没有其他进程可以从外部访问(我的意思是,干扰)它。我对吗? (2)在程序终止之前是否必须释放数组(在“f1”中分配)(或者在主程序终止后它是否会被释放)? (3)如果第二个问题的答案为“是”,那么如何释放在另一个函数中分配的数组呢?
注意:我希望保持在纯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);
}
答案 0 :(得分:17)
我假设,虽然功能" f1"已终止,分配的char数组仍然保持分配状态,直到主程序完全终止。
真。动态分配的内存与函数无关,它属于进程。
也就是说,分配的内存仍然属于main,没有其他进程可以从外部访问它。我是对的吗?
内存不属于main()
(用作函数),而是处理自身(其中main()
只是入口点)。在具有内存保护的系统中(每个进程与其他进程隔离),它无法从外部访问。但是,您可以以特定于系统的方式分配它,以跨进程共享内存。
我是否必须在程序终止之前释放数组(在" f1"中分配)(或者在主程序终止后立即释放)?
是。未分配的内存 - 大多数系统中的 - 在进程终止时由操作系统自动释放,但这取决于系统。 IMO甚至在操作系统执行时你应该总是解除分配,使用这种自动释放作为红旗(我忘记了解除分配,这是一个错误吗?我错过了什么?)。此外,如果f1
被调用1000次,那么每次快速吃掉所有可用内存都会泄漏内存。考虑服务器中的进程,它可能(并且应该)启动并运行多年。
如果第二个问题的答案是"是"那么如何释放在另一个函数中分配的数组呢?
分配内存的人也可以释放它。如果不可能,则调用者将对此类内存负责。例如,它是strdup()
的作用。在这种情况下,被调用的函数必须返回(以某种方式)指向已分配内存的指针(或可由另一个专用函数使用的句柄/令牌)。例如:
char* pBuffer = f1();
// Use it
free(pBuffer);
请注意,如果要隐藏此类内部指针,有许多技巧。您可以使用标记(例如,整数,字典中的键),typedef
或不透明类型。
答案 1 :(得分:6)
是的,分配有malloc()
的内存会一直保留,直到被释放。一个函数怎么能将可变大小的数据返回给它的调用者呢?
当程序退出时,将释放分配有malloc()
的所有内存。但是,在程序终止之前保留大量不需要的内存通常不是一个好主意,因为它会影响性能,或者系统可能耗尽虚拟内存。这对于长时间运行的程序来说可能是一个特别关注的问题,它们的内存使用有时会持续增长,直到它们使用所有可用的虚拟内存。
您在函数返回的指针上调用free()
。因此,在您的情况下,main()
可以在使用数组完成free(fData)
之后执行。{/ p>
任何C编程课程或教科书都应该涵盖这一点。
答案 2 :(得分:2)
malloc
在堆上分配内存,因此这个内存保持分配状态,直到它被free
函数释放,或者程序成功终止。
在您的情况下,您在ftemp
中释放了f1
,因此在函数终止后它不再存在。 fdata
仍然在堆上,main
可以访问它,因为您返回指向该分配位置的指针。
main
成功终止后,fdata
指向的内存将被释放。
因此,只要你不再需要记忆,就认为免费记忆是好的。在程序结束时释放块是没有意义的,因为当进程终止时(考虑到现代操作系统),所有程序的空间都被返回给系统。
答案 3 :(得分:1)
使用malloc
将在堆上分配内存,直到它free
为止。
这意味着您需要确保每个malloc都有相应的免费,也并不意味着没有其他进程无法访问您的数据。它只是一个地址的值。
在您的主要内容中,您必须free(fData)
以避免内存泄漏。
总结一下:
1)你的第一个假设是正确的,第二个和第三个假设是正确的。它将保持分配状态,但它不是主要的本地,并且在终止时没有绑定到进程。
2)是的,你必须释放它
3)使用从函数中获得的指针。如果没有从函数返回指向已分配数据的指针,请确保函数free
为它。
答案 4 :(得分:1)
是的,它还在堆里。但是,您对流程的概念感到困惑。除非您创建另一个流程(在* nix上使用fork
),否则它仍然是相同的流程。
在不使用时释放内存是一个好习惯。但是如果程序正常终止,系统将释放分配的内存。
像这样:
int main () {
char *fData = f1 (...);
//...
free(fData);
//...
}
答案 5 :(得分:1)
在C中可以使用两种基本类型的内存。两种类型是堆栈和堆。通常,在函数中创建的变量将在堆栈上分配,并在函数返回时释放。堆中分配的内存将保持不变,您有义务在程序中管理该分配。堆中的内存将保持分配状态,直到您使用引用数据块的指针(内存地址)释放为止。
对两者的一点阅读将有助于您理解。我要指出你有两个fData实例,每个实例都有自己的范围。两个指针都指向您分配的内存:
char *fData = malloc (length2 * sizeof (char));
..即使它们在代码执行时传入和传出范围。
答案 6 :(得分:1)
如果你没有释放你没有使用的内存,那么最终会累积 - 如果你用许多其他指针完成此操作 - 并且你的程序可能会耗尽内存。在使用free
函数释放内存块之后,我还建议为指针分配NULL
,因为这可以防止悬空指针,即使你已经释放指针,如果你尝试访问它,您可以获得未定义的行为,而NULL
指针上的访问和操作会导致崩溃,因此您可以轻松地跟踪问题