假设有以下函数:
char *getp()
{
char s[] = "hello";
return s;
}
由于这个函数返回一个指向函数内部的局部变量的指针,会导致内存泄漏吗?
P.S. 我仍在学习C语言,所以我的问题可能有点幼稚...
[更新]
那么,如果你想返回一个新的char[]
数组(比如子字符串函数),你应该返回什么?应该返回指向外部变量的指针吗?也就是说,一个不是函数内部局部变量的char[]
?
假设有以下函数:
char *getp()
{
char s[] = "hello";
return s;
}
由于这个函数返回一个指向函数内部的局部变量的指针,会导致内存泄漏吗?
P.S. 我仍在学习C语言,所以我的问题可能有点幼稚...
[更新]
那么,如果你想返回一个新的char[]
数组(比如子字符串函数),你应该返回什么?应该返回指向外部变量的指针吗?也就是说,一个不是函数内部局部变量的char[]
?
它不会导致内存泄漏,而是会导致悬空引用。局部变量在堆栈上分配并且一旦超出作用域就会被释放。因此,当函数结束时,您返回的指针不再指向您拥有的内存。这不是内存泄漏(内存泄漏是指您分配一些内存但没有释放它)。
[更新]: 为了能够返回在函数中分配的数组,您应该在堆(heap)中分配它,而不是在栈(stack)中分配,例如:
char *test() {
char* arr = malloc(100);
arr[0] = 'M';
return arr;
}
如果在使用完内存后,调用函数中没有使用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没有被销毁是因为它不在栈中,而是在堆中。然而,一旦程序结束,已分配的内存未被释放,引起了内存泄漏(即使这是在进程死亡后完成的)。
[更新]
如果你想从函数返回一个新的C字符串,你有两个选项。
例如:
//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中字符的数量。
这不是内存泄漏,因为内存被正确释放了。
但这是一个bug。 你有一个指向未分配内存的指针。这被称为悬空引用,在C语言中是常见错误源。 结果是未定义的。 直到运行时尝试使用该指针时,才会看到任何问题。
自动变量在函数调用结束时被销毁,您不能返回它们的指针。你所做的可以描述为“返回一个指向曾经持有s的内存块的指针,但现在未使用(但可能仍然有一些内容),并且很快将被完全填充其他内容”。
它不会导致内存泄漏,但会导致未定义的行为。这种情况特别危险,因为指针将指向程序堆栈中的某个位置,如果您使用它,将访问随机数据。这样的指针在写入时还可以用于破坏程序安全性并使其执行任意代码。
还没有人提到你可以通过告诉编译器你想要数组 "s" 具有 "静态存储期" 的方式来使这个构造有效(这意味着它的生命周期与程序一样长,就像全局变量一样)。你可以使用关键字 "static" 来实现:
char *getp()
{
static char s[] = "hello";
return s;
}
static
引用存储在堆上吗? - Andreas Grech我在将代码放入调试器并观察反汇编和内存窗口后,删除了我的早期答案。
问题中的代码无效并返回指向栈内存的引用,该内存将被覆盖。
然而,这个稍微不同的版本返回对固定内存的引用,并且工作正常:
char *getp()
{
char* s = "hello";
return s;
}
s
是一个栈变量 - 在函数结束时它会自动取消引用。然而,你的指针将不再有效,并且可能会引用任何时刻都可能被覆盖的内存区域。
arr[0] = 'M';
赋值是必要的吗?还是只是为了演示对arr
的非平凡操作? - user1717828