为什么我必须在指针上使用free而不是正常的声明?

时间:2009-03-09 17:23:36

标签: c pointers free

为什么我在声明指针时必须使用free():

int *temp = (int*)malloc(sizeof(int))
*temp = 3;

但不是在我这样做的时候:

int temp = 3;

8 个答案:

答案 0 :(得分:27)

正常声明放在堆栈上。当函数返回时,堆栈指针恢复到调用函数之前的值,因此内存会自动回收。

基于Malloc的声明是从'heap'分配的,这需要程序员管理分配和解除分配。

答案 1 :(得分:12)

你并不总是必须在指针上使用free,只需使用malloc声明的指针。您可以声明指向堆栈上的内存位置的指针

int a = 3;
int* p = &a;

并且当内存超出范围时,此内存(以及指针)也将自动处理掉。使用malloc在堆上分配相同的内存,因此您必须手动处理清理。

答案 2 :(得分:8)

因为您可以在堆栈和堆之间选择语言。

您想要在堆栈和堆之间进行选择的原因:

  • 堆上的变量故意不释放自己,以便您可以使用它们超出代码块或函数的范围。
  • 与堆
  • 相比,使用堆栈更有效
  • 在大多数编译器中,您无法在运行时选择堆栈上的对象或数组的大小,因此将在此处使用堆。

为什么无法自动释放堆:

因为没有办法知道你何时完成了记忆。有一些方法可以模拟垃圾收集,但这涉及到堆栈上没有更多变量并且堆上有一个指向堆上数据的指针。

有关Stack vs Heap的更多内容:

C语言允许您选择是否要在堆栈或堆上定义变量。

  • 当堆栈中的变量超出scope时会自动释放。
  • 堆上的变量不会自动释放。

malloc在堆上创建变量。一个简单的声明,如int x;在堆栈上创建一个变量。

See further reading on stack vs heap in my answer here

<强>指针:

只是为了澄清:指针变量是在堆栈上创建的,它们为堆上分配的数据保存一个内存地址。它们在32位系统上的堆栈上占用4个字节,在64位系统上占用堆栈上的8个字节。

答案 3 :(得分:5)

应该注意的是,C没有堆栈或堆的概念,尽管前面的答案在99%的时间内是正确的并且给出了很好的洞察力。

C为对象定义了三个存储持续时间:静态自动已分配。 (§6.2.4.1)

静态对象(例如全局变量)在整个程序的持续时间内可用。

只要变量在范围内,就会存在自动对象。一旦它超出范围,它们就不复存在了。

请注意,这是两个极端。 C为您提供了一个指向:分配的对象。 (搜索项将是动态分配的内存。)有了这些,告诉计算机对象应该何时开始和结束它们的存在。这是通过使用标准函数 malloc()(或衍生物)和 free()完成的。

严格来说,您不得致电 free()。或者你可以这样做(你必须阅读关于这一点的授权点的标准),但是你可以在 main()的末尾完成所有操作,就在程序终止之前。或者,让它留给操作系统为你做(大多数,如果不是全部的话)。但是这又是一个极端 - 当你调用 malloc()时,对象就会出现,当你的程序终止时出去。

我不应该在这里详细谈论​​实际意义:记忆是有限的。在内存不足之前,您只能分配这么多字节。对所有事情使用静态对象会太浪费;尝试重用块或一大块静态内存将是困难的,并且在任何情况下都类似于动态分配方法。对长寿命对象使用自动存储将迫使您使其范围尽可能大,无论如何大致对应于静态对象的范围。

-

现在,有些说明:

{
    int *temp = malloc(sizeof(int));
    *temp = 5;
    //free(temp);
}

请注意temp这里是一个自动对象。只有它的范围才会生存,结束于}。但是,它指向的对象已被分配。它将存在,直到你在其地址上调用free()。由于temp包含该地址的唯一副本,因此一旦temp超出范围,您将失去调用free()的机会。一些内存将永久分配,但不可用。这称为内存泄漏

垃圾收集是管理对象存储的另一种方法。 C中的实现可能如下所示:

{
    int *temp = gc_malloc(sizeof(int));
    *temp = 5;
}

在}的位置,计算机会决定丢失分配对象的最后一个引用temp,并且释放它是个好主意。

这是一个权衡,你不必担心free()对象(这不是一个小问题,因为简单的例子可能会让你思考),但gc_malloc()在这里比一个更复杂简单的malloc(),并且在{} temp超出范围的情况下执行的不可见代码。这是一个完全不同的主题,计算机如何决定temp是最后一个参考。 (一些实用的解决方案可能会涉及到围绕“int * temp”编写更多代码。)

答案 4 :(得分:3)

Alnitak是对的。我想指出“stack”的真正含义。

当一个程序进行函数调用时,它希望该函数做一些工作,然后返回并继续下一行代码。该函数无法知道函数完成时返回的位置。因此,机器有一个调用堆栈,用于在调用函数之前用于在程序中推送以下语句的地址的每个程序。 “return”语句只是弹出程序地址并跳转到它。

堆栈也是临时空间的便利便笺簿。可以写入堆栈的未使用区域。在C函数中声明局部变量就是这样。当函数返回时,不需要清理,释放或以其他方式处理堆栈,因为它只是一个临时空间,现在已超出范围。

相反,调用malloc()会从堆中分配内存,这会为程序显式留出内存,并且只要程序正在运行就会保留在范围内。因此,如果您没有free()内存,它将保持分配并被视为内存泄漏。

答案 5 :(得分:2)

free()的需要并不取决于你是否已经声明指针,而是取决于你是否malloc()内存。

就像Brian Bondy之前所说的那样,变量(“int number”,“char string[10]”,“float your_boat”等等会在超出范围时消失,就像你的代码留下一个功能块。因此,当您调用temp时,问题中的指针(“free()”)不会消失 - 相反,无论您在调用malloc()时分配的代码是什么都消失了。您的指针仍然停留在那里,即在您的示例代码之后立即说出“temp = &some_other_variable”,而不必再说“int *temp;”。

如果有人曾经实现了某项功能,那么他们也恰好打电话给malloc(),这会为您的程序提供内存,并且不需要您发布该数据,那么您可以说

int * temp = (int*)malloc(sizeof(int));

没有后来说

free(temp);

但这不是malloc()实施的方式。

答案 6 :(得分:0)

进一步使得this post进一步澄清事情。

答案 7 :(得分:-9)

这是一个非常好的问题,虽然许多人会回答它是堆栈和堆分配之间的区别,但根本的答案是说谎系统暴露了一些不应该的东西。

当您分配内存时,您不必担心将其恢复。系统应足够智能,以确定您无法再访问它(点或引用),因此它可以自动恢复内存。

像Java和C#这样的新语言就是这样做的。