假设您有以下功能:
char *getp()
{
char s[] = "hello";
return s;
}
由于函数返回指向要在外部使用的函数中的局部变量的指针,它是否会导致内存泄漏?
P.S。我还在学习C所以我的问题可能有点幼稚......
[更新]
所以,如果你想要返回一个新的char[]
数组(也就是说可能是一个子字符串函数),那么你究竟返回了什么?它应该是指向外部变量的指针吗?即一个char[]
不是函数的本地?
答案 0 :(得分:25)
它不会导致内存泄漏。它会引起悬垂的参考。局部变量在堆栈上分配,一旦超出范围就会被释放。因此,当函数结束时,您返回的指针不再指向您拥有的内存。这不是内存泄漏(内存泄漏是指分配一些内存而不释放内存)。
<强> [更新] 强>: 为了能够返回在函数中分配的数组,您应该将它分配到堆栈外(例如在堆中),如:
char *test() {
char* arr = malloc(100);
arr[0] = 'M';
return arr;
}
现在,如果你在完成使用后没有free
调用函数中的内存,你就会有内存泄漏。
答案 1 :(得分:13)
不,它不会泄漏,因为它在getp()结束后被破坏;
它将导致未定义的行为,因为现在您有一个指向内存区域的指针,该内存区域不再包含您认为它的功能,任何人都可以重复使用。
如果将该数组存储在堆上,而不执行对free()的调用,则会发生内存泄漏。
char* getp(){
char* p = malloc(N);
//do stuff to p
return p;
}
int main(){
char* p = getp();
//free(p) No leak if this line is uncommented
return 0;
}
这里,p不会被破坏,因为它不在堆栈中,而是在堆中。但是,一旦程序结束,分配的内存就没有被释放,导致内存泄漏(即使它在进程死亡时完成)。
<强> [UPDATE] 强>
如果你想从一个函数返回一个新的c-string,你有两个选择。
例如:
//doesnt exactly answer your update question, but probably a better idea.
size_t foo (const char* str, size_t strleng, char* newstr);
在这里,你必须在调用foo函数之前为newstr(可能是堆栈OR堆)分配内存。在这种特殊情况下,它将返回newstr中的字符数量。
答案 2 :(得分:8)
这不是内存泄漏,因为内存正在正确释放。
但这是一个错误。你有一个指向未分配内存的指针。它被称为dangling reference,是C中常见的错误来源。结果未定义。在尝试使用该指针时,在运行时才会看到任何问题。
答案 3 :(得分:3)
在函数调用结束时销毁自动变量;你不能返回指向它们的指针。你正在做的事情可以被描述为“返回一个指向过去用于保存s的内存块的指针,但现在未使用(但可能仍然有一些内容,至少目前为止)并且会迅速填充某些东西完全是。“
答案 4 :(得分:2)
它不会导致内存泄漏,但会导致未定义的行为。这种情况特别危险,因为指针将指向程序堆栈中的某个位置,如果使用它,您将访问随机数据。这样的指针在写入时也可用于危害程序安全性并使其执行任意代码。
答案 5 :(得分:2)
没有其他人提到另一种方法可以使这个结构有效:告诉编译器你希望数组“s”具有“静态存储持续时间”(这意味着它在程序的生命周期中存在,像一个全局变量)。您可以使用关键字“static”执行此操作:
char *getp()
{
static char s[] = "hello";
return s;
}
现在,它的缺点是现在只有一个的s实例,在每次调用getp()函数之间共享。使用您编写的功能,这无关紧要。在更复杂的情况下,它可能不会做你想要的。
PS:通常的局部变量具有所谓的“自动存储持续时间”,这意味着在调用函数时,变量的新实例将存在,并在函数返回时消失。有一个相应的关键字“auto”,但如果你不使用“static”,它就暗示了,所以你几乎从未在现实代码中看到它。
答案 6 :(得分:1)
将代码放入调试器并观察反汇编和内存窗口后,我删除了我之前的答案。
问题中的代码无效,并返回对堆栈内存的引用,该引用将被覆盖。
然而,这个略有不同的版本会返回对固定内存的引用,并且工作正常:
char *getp()
{
char* s = "hello";
return s;
}
答案 7 :(得分:0)
s
是一个堆栈变量 - 它在函数末尾自动解除引用。但是,您的指针将无效,并且将引用可能在任何时候被覆盖的内存区域。