精华内容
下载资源
问答
  • C语言 栈和堆详解

    2018-09-29 15:02:07
    关于C语言malloc的一个问题,自动手动分配内存的区别是什么? //定义一个结构 typedef struct linkedlist* nextnode; typedef struct linkedlist{ char c; nextnode next; }link; //第一种 link* newLink(){ ...

    关于C语言malloc的一个问题,自动和手动分配内存的区别是什么?
    //定义一个结构

    typedef struct linkedlist* nextnode; 
    typedef struct linkedlist{
    	char c;
    	nextnode next;
    }link;
    
    //第一种 
    link* newLink(){
    	link* l;
    	l=(link*)malloc(sizeof(link));
    	l->next=NULL;
    	return l;
    }
    
    //第二种,和上面的效果一样! 
    link* newLink(){
    	link a={};
    	link* b=&a;
    	return b;
    }
    

    C语言新手,想问一下,第一种和第二种的区别是什么?我感觉两个效果是一样的,都能返回我所需要的结构指针。

    — 以上是问题 —

    — 以下是回答 —

    作者:Tabjy
    链接:https://www.zhihu.com/question/36499626/answer/142454973
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    先上结论:Local variables (局部变量),也就是你的第二种写法,会在离开 scope (作用域),也就是函数结束时被销毁掉。(严格上来说还在内存那个位置,并没有被销毁,下面会有解释)而用 malloc()申请的内存只有在整个程序退出之后,或者你手动调用 free() 的时候被释放掉。
    以下是解释
    要理解这个问题,首先要知道内存的结构。一般来说内存分为了一下四个部分:

    1. Stack (栈内存):主要是用来存储 function calls (函数调用)local variables 的空间,其本质就是一个 Stack(栈)。最底层的便是 main() 函数,每调用一个函数时就会执行 push 操作,每当函数 return 时便执行 pop 操作。什么时候 main() 也被 pop 了,整个程序也就结束了。(如果这个 stack 变得太高以至于超出了最大内存地址,就会出现所谓的 stackoverflow
    2. HEAP(堆内存):主要是用来存储由 malloc() 等申请的内存位置。如果 malloc() 返回 null 的话就往往表示这一块空间已经用完了。
    3. Static (静态内存):不太确定这个翻译。这里的变量的生命周期与整个程序相同,即在进程创建是被申明,在程序退出时被销毁。 global variables(全局作用域变量), file scope variables(文件作用域变量)被 static 关键字修饰的变量会存在这里。
    4. Code:关于这方面的划分,有不同的理解。可以简单的理解为程序的二进制指令和一些其他必要的东西。

    这个问题只涉及到 stackHEAP 内存。刚刚说了,所有的 local variable 按照 stack 的形式被存储在 stack memory 中。这个 stack 由一个 stack pointer 来管理,它所指向的内存地址按照 function call 的运行情况来增加或减少。比如 函数A 调用了 函数B,函数B 就会被 push 到 函数A 之上,原本的 stack pointer 也会从 函数A 移动到 函数B。pop 函数B 时 stack pointer 的操作也是同理,那么理论上包含在 函数B 中的变量已经被释放,为什么大多数情况还是能在 函数A 中得到这个值呢?因为C语言在设计之初就是以性能为优先,所以 pop 时只会移动 stack pointer 而不会花费额外的资源去覆盖掉之前的内存。如果在使用那个 pointer 之前并没有再调用其他的函数,那么这么 pointer 所对应的地址就不会被覆盖掉。

    请考虑以下情况:

    int* getAnswer() {
      int a = 42;
      return &a;
    }
    
    void overwriteMemoryWithGarbageData() {
      int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    }
    
    int main() {
      int *answerToLife = getAnswer();
      overwriteMemoryWithGarbageData();
      printf("%d\n", *answerToLife);
      return 0;
    }
    

    这段代码便不会得到 生命、宇宙以及任何事情的终极答案,而是像 9 这样的垃圾数据。此时,正确的处理方法便是:

    int* getAnswer() {
      int *ret = malloc(sizeof(int));
      *ret = 42;
      return ret;
    }
    

    记住,系统永远不会主动释放 HEAP 中的内存,因为C语言中并没有垃圾回收之类的机制,滥用 malloc() 会导致 HEAP 很快被填满造成内存泄露。所以在用完之后尽量记得 free(void *__ptr):

    int main() {
      int *meaningOfLife = getAnswer();
      overwriteMemoryWithGarbageData();
      printf("%d\n", *meaningOfLife);
      free(meaningOfLife);
      return 0;
    }
    

    **在实际使用中,只要是需要被自身以外的函数调用的变量,请全部从 HEAP 中申请。**而申请者也需要记住在使用完毕后及时 free() 。
    解释完毕
    这里只是 CS 大一学生,并不保证以上内容的正确性或准确性,总之考试是这么答的就是了(当然没有写这么多)。因为学习环境是英文,而且无法保证翻译的准确定,以上术语均使用英文(某些在第一次出现时给出了我所认为正确的翻译)。如于事实有所出入,还请多多包涵。

    作者:Tabjy
    链接:https://www.zhihu.com/question/36499626/answer/142454973
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    展开全文
  • C语言栈和堆的区别

    2019-02-28 11:15:05
    就像装数据的桶或箱子 我们先从大家比较熟悉的说起吧,它是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取。这就如同我们要取出放在箱子里面底下的东西(放入的比较早的物体),我们首先...

    栈就像装数据的桶或箱子
    我们先从大家比较熟悉的栈说起吧,它是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取。这就如同我们要取出放在箱子里面底下的东西(放入的比较早的物体),我们首先要移开压在它上面的物体(放入的比较晚的物体)。

    堆像一棵倒过来的树
    而堆就不同了,堆是一种经过排序的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。由于堆的这个特性,常用来实现优先队列,堆的存取是随意,这就如同我们在图书馆的书架上取书,虽然书的摆放是有顺序的,但是我们想取任意一本时不必像栈一样,先取出前面所有的书,书架这种机制不同于箱子,我们可以直接取出我们想要的书。

    0.申请方式和回收方式不同
    不知道你是否有点明白了,堆和栈的第一个区别就是申请方式不同:栈(英文名称是stack)是系统自动分配空间的,例如我们定义一个 char a;系统会自动在栈上为其开辟空间。而堆(英文名称是heap)则是程序员根据需要自己申请的空间,例如malloc(10);开辟十个字节的空间。由于栈上的空间是自动分配自动回收的,所以栈上的数据的生存周期只是在函数的运行过程中,运行后就释放掉,不可以再访问。而堆上的数据只要程序员不释放空间,就一直可以访问到,不过缺点是一旦忘记释放会造成内存泄露。还有其他的一些区别我认为网上的朋友总结的不错这里转述一下:

    1.申请后系统的响应

    栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

    堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆。结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的 delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
    也就是说堆会在申请后还要做一些后续的工作这就会引出申请效率的问题。

    2.申请效率的比较
    根据第0点和第1点可知。

    栈:由系统自动分配,速度较快。但程序员是无法控制的。

    堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

    3.申请大小的限制
    栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
    堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

    堆和栈的区别可以引用一位前辈的比喻来看出:
    使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
    使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。比喻很形象,说的很通俗易懂,不知道你是否有点收获

    展开全文
  • c语言 栈和堆的区别

    2013-03-21 15:58:18
    http://wenku.baidu.com/view/ee7ec08da0116c175f0e48a1.html 写的很好的一篇关于 堆和栈的区别的文章。

    http://wenku.baidu.com/view/ee7ec08da0116c175f0e48a1.html

    写的很好的一篇关于 堆和栈的区别的文章。


    展开全文
  • C语言栈

    2018-04-11 16:39:20
    ---------------------------------------------------------------------------------------------------转自:https://blog.csdn.net/x_chengqq/article/details/51190678这里说的是C语言程序内存分配中的堆和栈。...

    ---------------------------------------------------------------------------------------------------

    转自:https://blog.csdn.net/x_chengqq/article/details/51190678


    这里说的是C语言程序内存分配中的堆和栈。下面先谈谈C语言的内存管理:


    可执行程序在存储时(没有调到内存)分为代码区(text)、数据区(data)和未初始化数据区(bss)3个部分。

    (1)代码区(text segment)。存放CPU执行的机器指令(machine instructions)。通常,代码区是可共享的(即另外的执行程序可以调用它),因为对于频繁被执行的程序,只需要在内存中有一份代码即可。代码区通常是只读的,使其只读的原因是防止程序意外地修改它的指令。另外,代码区还规划了局部变量的相关信息。

    (2)全局初始化数据区/静态数据区(initialized data segment/data segment)。该区包含了在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据(如字符串常量)。

    (3)未初始化数据区(BSS区,uninitialized data segment),存入的是全局未初始化变量。BSS区的数据在程序开始执行之前被内核初始化为0或者空指针(NULL)。


    上图表示可执行代码存储时结构和运行时结构的对照图。一个正在运行着的C编译程序占用的内存分为代码区、初始化数据区、未初始化数据区、堆区和栈区5个部分。

    (1)代码区。代码区指令根据程序设计流程依次执行,对于顺序指令,则只会执行一次(每个进程),如果反复,则需要使用跳转指令,如果进行递归,则需要借助栈来实现。

    代码区的指令中包括操作码和要操作的对象(或对象地址引用)。如果是立即数(即具体的数值),将直接包含在代码中;如果是局部数据,将在栈区分配空间,然后引用该数据地址;如果是BSS区和数据区,在代码中同样将引用该数据地址。

    (2)全局初始化数据区/静态数据区。只初始化一次。

    (全局变量的值可以改变

    1. #include <iostream>  
    2. using namespace std;  
    3.    
    4. int a = 8;  
    5. int main(){  
    6.     a = 4;  
    7.     cout<<a;  
    8. }  

    输出     4

    (3)未初始化数据区(BSS)。在运行时改变其值。

    (4)栈区。由编译器自动分配释放,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。每当一个函数被调用,该函数返回地址和一些关于调用的信息,比如某些寄存器的内容,被存储到栈区。然后这个被调用的函数再为它的自动变量和临时变量在栈区上分配空间,这就是C实现函数递归调用的方法。每执行一次递归函数调用,一个新的栈框架就会被使用,这样这个新实例栈里的变量就不会和该函数的另一个实例栈里面的变量混淆。

    (5)堆区(heap)。用于动态内存分配。堆在内存中位于BSS区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时有可能由OS回收。

    之所以分成这么多个区域,主要基于以下考虑:

    一个进程在运行过程中,代码是根据流程依次执行的,只需要访问一次,当然跳转和递归有可能使代码执行多次,而数据一般都需要访问多次,因此单独开辟空间以方便访问和节约空间。

    临时数据及需要再次使用的代码在运行时放入栈区中,生命周期短。

    全局数据和静态数据有可能在整个程序执行过程中都需要访问,因此单独存储管理。

    堆区由用户自由分配,以便管理。

    下面是网上一个典型的例子来帮助理解C程序内存分配:

    1. int a = 0;     //a在全局已初始化数据区  
    2. char *p1;     //p1在BSS区(未初始化全局变量)  
    3.   
    4. void main()  
    5. {  
    6.      int b;     //b在栈区  
    7.      char s[] = "abc";    //s为数组变量,存储在栈区,“abc”为字符串常量,存储在已初始化数据区  
    8.      char *p1, p2;    //p1、p2在栈区   这里我觉得p2不是指针类型,下面直接malloc有问题,用dev C显示不是指针,VC编译器下也不是指针类型  
    9.      char *p3 = "123456";    //123456\0在已初始化数据区,p3在栈区  
    10.      static int c = 0;    //c为全局(静态)数据,存在于已初始化数据区  
    11.      //另外,静态数据会自动初始化  
    12.      p1 = (char *)malloc(10);   //分配得来的10个字节的区域在堆区  
    13.      p2 = (char *)malloc(20);   //分配得来的20个字节的区域在堆区  
    14.      free(p1);  
    15.      free(p2);  
    16. }  

    内存分配方式:

    在C语言中,对象可以使用静态或动态的方式分配内存空间。

    静态分配:编译器在处理程序源代码时分配。

    动态分配:程序在执行时调用malloc库函数申请分配。

    静态内存分配是在程序执行之前进行的,因而效率比较高,而动态内存分配则可以灵活处理数据。

    静态与动态内存分配的主要区别如下:

    静态对象是有名字的变量,可以直接对其进行操作;动态对象是没有名字的变量,需要通过指针间接地对它进行操作。

    注:这里我的理解有     如果我们在程序中有写malloc,它是静态对象还是动态对象(这是针对“动态对象是没有名字的变量”)

             解答:我的理解有问题,malloc出来的就是在堆中开辟内存空间,是没有名字的。

             如:p1 = (char *)malloc(sizeof(int));            //此行代码分配了一个int类型大小的区域在堆区(对象),然后返回对象在内存中的地址,接着这个地址被用来初始化指针对象p1,对于动态分配的内存唯一的访问方式是通过指针间接地访问。

    1. int *p;       //p中的地址所指向的内容  
    2. p;              //p这个变量的内容,这里p存的是地址,则为地址  
    3. &p;           //取p的地址  

    静态对象的分配与释放由编译器自动处理;动态对象的分配与释放必须由程序员显式地管理,它通过malloc()和free()两个函数(C++中为new和delete运算符)来完成。


    下面就来正式讲讲栈与堆的区别:

    1、申请方式不同

    2、管理方式不同。堆容易产生内存泄露。(这个就看程序员啦)

    3、空间大小不同。

    栈是向低地址扩展的数据结构,是一块连续的内存区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,当申请的空间超过栈的剩余空间时,将提示溢出。因此,用户能从栈获得的空间较小。

    堆是向高地址扩展的数据结构(它的生长方向与内存的生长方向相同),是不连续的内存区域。因为系统是用链表来存储空闲内存地址的,且链表的遍历方向是由低地址向高地址。由此可见,堆获得的空间较灵活,也较大。

    4、系统响应:

    栈:只要栈的空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

    堆:操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的free语句才能正确的释放本内存空间。另外,找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

    对于堆来讲,频繁的malloc/free势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈就不会存在这个问题。

    5、增长方向不同

    6、申请效率不同

    堆的效率要低于栈。

    -----------------------------------------------------------------------------------------------------

     valgrind通过伪造malloc()可以监控分配在堆上的数据。当
    程序想分配堆存储器时,valgrind将会拦截你对malloc()和
    free()的调用,然后运行自己的malloc()和free()。valgrind
    的malloc()会记录调用它的是哪段代码和分配了哪段存储器。程
    序结束时,valgrind会汇报堆上有哪些数据,并告诉你这些数据
    是由哪段代码创建的。


     valgrind --leak-check=full ./spy

    展开全文
  • C语言栈堆和静态区

    2014-01-05 14:23:32
    堆和栈都有自己的特性,这里先不做讨论。再打个比方:一层教学楼,可能有外语教室,允许外语系学生老师进入;还可能有数学教师,允许数学系学生老师进入;还可能有校长办公室,允许校长进入。同样,内存也是这样...
  • 注意是:使用要在mallocfree之间,在此之间不能赋值其他值,有可能吃内存。 malloc(x)时 x<16时都会申请16个字节。 int p =(intp)malloc(20),malloc返回的值时SIZE_T类型,所以要转化。 ...
  • C语言栈、函数递归

    千次阅读 2014-09-23 16:58:02
    是一个后进先出的压入(push)弹出(pop)式数据结构。在程序运行时,系统每次向中压入一个对象,然后指针向下移动一个位置。当系统从中弹出一个对象时,最近进栈的对象将被弹出。然后指针向上移动一个位置...
  • 8种机械键盘轴体对比本人程序员,要买一个写代码的键盘,请问红轴茶轴怎么选?1.现代操作系统内存管理主流的操作系统(Windows,Linux)都采用虚拟内存管理的方式,具体说就是:页式管理、段式管理、段页式管理。操作...
  • C语言栈和堆的区别

    千次阅读 2018-05-31 12:27:48
    关于栈和堆简单可以理解为: heap(堆):是由malloc之类函数分配的空间所在地。地址是由低向高增长的。 stack(栈):是自动分配变量,以及函数调用的时候所使用的一些空间。地址是由高向低减少的。 预备知识...
  • 动态存储区在程序裕兴的过程中可能内存被程序员或者是编译器释放掉,静态存储区只有当程序运行完后才会被释放内存2:c语言中,数据的存储区分为动态存储静态存储,其中动态存储又分为堆和栈内存区域3:是一个...
  • 这里说的是C语言程序内存分配中的堆和栈。下面先谈谈C语言的内存管理: 可执行程序在存储时(没有调到内存)分为代码区(text)、数据区(data)未初始化数据区(bss)3个部分。 (1)代码区(text segment)。...
  • C语言中的堆和栈

    2017-12-14 21:30:18
    C语言堆和栈
  • C语言栈和堆 内存

    2013-08-26 18:06:28
    的特点 是 速度快,存储小,自动释放内存 :比如函数 的特点是,速度稍慢于,存储空间大,手动释放内存,调用free函数: 比如malloc定义大量存储空间, 如果 不释放内存,将一直占用内存空间,知道退出程序
  • 本篇文章主要介绍了什么是栈(Stack) 、什么是堆( Heap),以及栈和堆的优缺点,同时介绍了应该什么时候使用堆和栈,有需要的朋友可以参考下
  • 上分配内存回收都是...在C++中,内存分成5个区,他们分别是、自由存储区、全局/静态存储区常量存储区。 ,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常...
  • c语言中的

    2019-09-22 04:09:16
    区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。...全局区(静态区)(static)—,全局变量静态变量的存储是放在一块的,初始化的全局变量静态变量在一块区域, 未初始化的全...
  • C语言中的栈和堆

    2016-12-29 19:12:00
    内存由编译器分配释放,内存由程序分配释放。 1、C语言中的动态内存 C语言程序语言中的动态数据存储区主要有两大类:一类是(STACK)内存区域,另一类是(HEAP)内存区域。他们都是在程序运行的过程中...
  • 动态分配由alloca函数进行分配,但是的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。  分 配效率:是机器系统提供的数据结构,计算机会在底层对提供支持:分配专门的寄存器...
  • C语言堆和栈的使用

    2020-08-03 17:33:19
    本文介绍了C语言堆和栈之间的区别、使用等内容。
  • 在计算机领域,堆栈是一个不容忽视的概念,我们编写的C语言程序基本上都要用到。但对于很多的初学着来说,堆栈是一个很模糊的概念。
  • C语言里面的栈和堆

    2014-04-15 14:48:31
    动态分配内存是在上,直接创建数组是在中,虽然都是在内存,但性能还是有点区别的 是机器系统提供的数据结构,计算机会在底层对提供支持:分配专门的寄存器存放的地址,压栈出栈都有专门的指令执行,这就...
  • C语言 堆和栈的区别

    2009-06-28 22:55:51
    C语言 堆和栈的区别

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,579
精华内容 1,031
关键字:

c语言栈和堆

c语言 订阅