[译]栈和堆的区别

栏目: C · 发布时间: 6年前

内容简介:中文原文:英文原文:校对:

栈和堆的区别

中文原文: 栈和堆的区别

英文原文: Memory:Stack vs Heap

校对: xiaobai22

目录

  • 栈和堆的区别
  • 栈和堆的优缺点

  • 例子
  • 什么时候使用堆
  • 关联文章

栈和堆的区别

到目前为止,我们已经知道如何声明基础变量类型,例如: int , double 等以及复杂类型例如:数组和结构体。在 C语言 中,我们使用和其他语言诸如MATLAB,Python相同的语法声明它们,并把这些变量推到栈里。

什么是栈?这是计算机内存的特定区域,它存储每个函数创建的临时变量(包括 main() 函数)。栈使用“LIFO”数据结构,由CPU管理和优化。每当函数声明一个新变量,它就会被推入栈。当函数退出时,所有被该函数推入栈的变量会被释放(这代表,它们已经被删除)。一旦栈的变量释放,此内存区可以被其他栈变量使用。

使用栈保存变量的优点:CPU帮你管理内存。你不需要手动分配和释放。更重要的是,CPU可以高效的组织内存,读写栈变量会非常快。

理解栈的关键 : 当函数退出时 ,它推入栈的所有变量会被弹出(永远丢失)。栈变量本质是局部的。这涉及到我们之前了解的 变量作用域 或 局部和全局变量。在C语言编程通常会遇到此类BUG:从函数外部企图读取函数内部的变量(在函数退出之后)。

栈另一个需要注意的特征是:保存在栈的变量是有大小限制的。堆的情况却不一样。

栈的总结:

  • 栈的增长和缩容发生在函数推入和弹出局部变量时
  • 不需要你自己管理内存,变量会自动分配和释放
  • 栈有大小限制
  • 栈变量仅存在于创建它们的函数运行的时候

堆是计算机的内存区,它不会帮你自动管理,也不由CPU管理。堆有更大的空间。你需要使用 C语言内置函数 malloc()calloc() 分配内存到堆。当不再使用这块内存时,你负责使用 free() 进行释放。如果没做这步,你的程序会发生内存泄露。堆上的内存仍然被占用(不能被其他进程使用)。正如我们在调试中看到的,用 valgrind 工具,帮助检测内存泄漏。

和栈不一样,堆没有大小限制(除了物理内存限制)。堆的读写稍微比较慢,因为必须使用指针访问堆上的内存。我们在后面会讨论指针。

和栈不一样,其他函数和你程序上的任何地方都可以访问堆上创建的变量。堆本质是全局的。

栈和堆的优缺点

  • 访问非常快
  • 不必显式的分配变量
  • CPU有效的管理,不会产生内存碎片
  • 仅用于局部变量
  • 有大小限制(不同操作系统有区别)
  • 大小不能被调整

realloc()

例子

这是一个简短的程序,创建变量到栈。

#include 

double multiplyByTwo (double input) {
  double twice = input * 2.0;
  return twice;
}

int main (int argc, char *argv[])
{
  int age = 30;
  double salary = 12345.67;
  double myList[3] = {1.2, 2.3, 3.4};

  printf("double your salary is %.3f\n", multiplyByTwo(salary));

  return 0;
}

double your salary is 24691.340

在10,11,12行我们声明了变量:int ,double,长度为3的浮点型数组。 main() 进行分配的时候,这3个变量被推到栈。当 main() 函数退出(程序停止),这些变量会被弹出栈。同样的,在函数 multiplyByTwo() 有2个 double 型的变量,会被推到栈。 multiplyByTwo() 退出,这2个变量会被弹出栈,永远消失。

顺便提一句,有一种方法可以告诉C语言,即使创建函数退出后,仍然可以保留栈变量,就是在声明变量时使用 static 关键字。因此,使用 static 关键字声明的变量类似于全局变量,但只能在创建它的函数中可见。这是一种奇怪的结构,除非在非常特殊的情况下,否则你可能不需要它

这是另一个版本,分配所有变量到堆而不是栈:

#include 
#include 

double *multiplyByTwo (double *input) {
  double *twice = malloc(sizeof(double));
  *twice = *input * 2.0;
  return twice;
}

int main (int argc, char *argv[])
{
  int *age = malloc(sizeof(int));
  *age = 30;
  double *salary = malloc(sizeof(double));
  *salary = 12345.67;
  double *myList = malloc(3 * sizeof(double));
  myList[0] = 1.2;
  myList[1] = 2.3;
  myList[2] = 3.4;

  double *twiceSalary = multiplyByTwo(salary);

  printf("double your salary is %.3f\n", *twiceSalary);

  free(age);
  free(salary);
  free(myList);
  free(twiceSalary);

  return 0;
}

正如你所看到的,使用 malloc() 分配内存到堆和使用 free() 释放,这不是大问题,但有点麻烦。另外一个需要注意的是到处都是星符号。它们是什么?答案是,它们是指针。 malloc() 处理指针,而不是真实的值。我们后面会更详细讨论指针。指针在C语言是一种特殊的数据类型,它保存地址在内存而不是真实的值。因此在上面第5行,2个变量都不是 double , 但它们是指向浮点型的指针。变量double 保存了一个地址在内存。

什么时候使用堆

什么时候使用堆?什么时候使用栈?如果你要分配一块大内存和你需要保留这个变变量很长时间,那么你就要分配它们到堆。如果你处理的是相对小的变量,只需要存活在函数使用期间,那么你可以使用栈,它更容易更快。如果你需要可以动态改变大小的变量例如:数据和结构体,那你需要分配它们到堆,用动态内存分配函数 mallco() calloc() realloc()free() 手动管理内存。我们会讨论动态分配数据结构在讨论完指针后。


以上所述就是小编给大家介绍的《[译]栈和堆的区别》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Realm of Racket

Realm of Racket

Matthias Felleisen、Conrad Barski M.D.、David Van Horn、Eight Students Northeastern University of / No Starch Press / 2013-6-25 / USD 39.95

Racket is the noble descendant of Lisp, a programming language renowned for its elegance and power. But while Racket retains the functional goodness of Lisp that makes programming purists drool, it wa......一起来看看 《Realm of Racket》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器