假设我们有以下情况。
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] = ' ';
return output;
}
int main() {
char* input = "Hello";
char* output = halfString(input);
printf("%sn",output);
free(output);
}
调用 "free(output(" 是否会释放 main 本地的 char* 输出内存,并释放 halfString(( 本地的 char* 输出的内存?或者 halfString(( 本地的 char* 输出是否仍然存在内存泄漏?
任何帮助,不胜感激。
没有内存泄漏。
但是,您似乎对堆分配的工作原理感到困惑。这里只分配了一块内存,它不是halfString()
或main()
的"本地"。分配的区块存在于堆中,并且不限定为特定代码块。
malloc()
返回指向它的指针。然后,您将该指针返回到 main()
,但指针的值仍然相同:它指向内存中的相同地址,相同的堆块。 然后main()
正确地释放它。
作为设计考虑,这通常不是最好的做法。通常,调用方不一定知道 halfString()
返回的指针指向分配了malloc()
的块,并且他们需要free()
该块。这必须非常清楚和仔细地记录在案。更好的解决方案可能是提供一个执行释放的freeHalfString()
函数;然后,从维护的角度来看,这两个函数可以放在同一个位置并同时维护,这样调用方就不必担心缓冲区是如何分配的,或者如何释放它。
(正如其他人指出的那样,您也有缓冲区溢出,因为您需要分配 strlen(input) + 1
个字节来包含 NULL 终止符。
代码大多是正确的,因为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] != ' '; i++)
...
您似乎混淆了两个相关项目:缓冲区和指针。缓冲区是一个内存块,在您的问题的上下文中,它是使用 malloc()
分配的。指针是相关的,因为它指向缓冲区,但它不是缓冲区本身。
在 halfString()
函数中,分配缓冲区,并将该缓冲区的地址(指针(存储在本地output
中。然后,您将它返回给调用方 main()
,恰好该调用方具有指向同一缓冲区的同名变量。
现在,在 main()
中,当您free(output);
不是在释放指针时,您是在释放指针指向的缓冲区。缓冲区的分配位置无关紧要,重要的是缓冲区已分配(并且尚未释放(。在此调用之后,main 函数的 output
变量仍然存在,并且它仍然具有曾经有效缓冲区的地址 - 但当然不能使用该缓冲区,因为它不再有效。
现在关于你的问题"是否存在内存泄漏?"——你已经错误地分配了一个缓冲区,然后你释放了同一个缓冲区,所以没有链接。始终正确配对 malloc 和自由,您将保持良好状态。
free()
将释放在被调用函数本身中分配的内存。 它不是任何函数的本地,因为malloc allocates memory on heap
.
您称之为 local memory
的内容位于函数返回时将被释放的stack
上。
因此,使用 malloc
完成的分配heap
,您使用的过程将释放在调用函数中分配的内存。
此代码将正常工作(如果其他人提到的 off-byone 错误已修复(。 main
中的调用将释放 halfString
中分配的内存。
没有"主输出本地内存"。 main 的本地是输出指针,它是在堆栈上分配的,当 main 退出时将超出范围。
没有内存泄漏。系统知道有多少内存与指针相关联,并且由于您无法释放分配的malloc的部分内存块,因此它将释放所有内存块。