返回一个指向自动variables的指针
假设你有以下function:
char *getp() { char s[] = "hello"; return s; }
由于该函数正在返回一个指向外部函数中的局部variables的指针,会导致内存泄漏吗?
PS我仍然在学习C,所以我的问题可能有点天真…
[更新]
所以,如果说你想返回一个新的char[]
数组(也许是一个子string函数),你准确返回什么? 它应该是指向外部variables的指针吗? 即不是函数本地的char[]
?
它不会导致内存泄漏。 这将引起一个悬而未决的参考。 局部variables分配在堆栈上,一旦超出范围就会被释放。 因此,当函数结束时,您返回的指针不再指向您拥有的内存。 这不是内存泄漏(内存泄漏是当你分配一些内存,而不是释放它)。
[更新] :为了能够返回一个在函数中分配的数组,你应该在堆栈之外(例如在堆中)分配它:
char *test() { char* arr = malloc(100); arr[0] = 'M'; return arr; }
现在,如果您在完成使用后没有free
调用函数中的内存,则会发生内存泄漏。
不,它不会泄漏,因为它在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]
如果你想从一个函数返回一个新的Cstring,你有两个select。
- 将其存储在堆中(如上面的例子或者像这个实例那样返回一个重复的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(可能是堆栈或堆)分配内存。 在这种情况下,它会返回newstr中的字符数量。
这不是内存泄漏,因为内存正在正确释放。
但这是一个错误。 你有一个指向未分配内存的指针。 它被称为悬空参考 ,是C中常见的错误来源。 结果是不确定的。 当您尝试使用该指针时,直到运行时才会看到任何问题。
自动variables在函数调用结束时被销毁; 你不能返回一个指针给他们。 你所做的事情可以被描述为“返回一个指向内存块的指针,但是现在这个指针还没有被使用(但是可能还有其他内容,至less现在是这样),并且会很快被一些东西所填充其他的完全是“。
它不会导致内存泄漏,但会导致未定义的行为。 这种情况特别危险,因为指针会指向程序堆栈的某个地方,如果你使用它,你将会访问随机数据。 这样的指针,当通过写入,也可以用来危害程序的安全性,并使其执行任意代码。
没有人还提到了另一种可以使这个构造有效的方式:告诉编译器,你希望数组“有”静态存储持续时间“(这意味着它在程序的整个生命周期中,像全局variables)。 你用关键字“static”来做到这一点:
char *getp() { static char s[] = "hello"; return s; }
现在,其缺点是现在只有一个 s的实例,在getp()函数的每次调用之间共享。 用你写的这个function,那不会有问题。 在更复杂的情况下,它可能不会做你想要的。
PS:通常的局部variables有所谓的“自动存储时间”,这意味着当调用函数时,variables的新实例被引入,函数返回时消失。 有一个对应的关键字“自动”,但它仍然是暗示,如果你不使用“静态”,所以你几乎从来没有看到它在现实世界的代码。
在将代码放入debugging器并观察反汇编和内存窗口之后,我删除了以前的答案。
问题中的代码无效,并返回对堆栈内存的引用,这些内存将被覆盖。
然而,这个略有不同的版本返回了固定内存的引用,并且工作正常:
char *getp() { char* s = "hello"; return s; }
s
是一个堆栈variables – 它在函数结束时会自动取消引用。 但是,您的指针将不会有效,并且会指向可能在任何时候被覆盖的内存区域。