C++学习之旅3种数据管理方式----自动存储、静态存储、动态存储

来源:互联网 发布:软件行业营改增政策 编辑:程序博客网 时间:2024/06/13 01:45

自动存储、静态存储和动态存储

根据分配内存的方法,C++有3中分配内存的方式:自动存储、静态存储和动态存储(有时候也叫做自由存储空间或栈)。在存在的时间长短方面。以这3主公方式分配的数据对象各不相同。下面简要介绍一下每种类型


自动存储


在函数内部定义的常规变量使用自动存储空间,被称为自动变量(局部变量)。当它们所属的函数被调用时,会自动在栈空间上为它们分配存储空间。在该函数结束时栈空间释放、其生命也会自动消亡。
比如
这里写图片描述
这里写图片描述
根据结果我们可以清楚的看到,在函数调用的时候,为n数组在栈空间上开辟了20个字节的空间。也可以使用并且打印。但是当函数调用结束以后这段空间就会被自动释放。当然里面存储的数据也就会丢失。那就有人会发现这样一个问题。如下

int fun(void){    int num = 9;    return num;}int main(){    using namespace std;    int temp = fun();    cout << "temp = " << temp << endl;    return 0; }//执行结果temp = 9;

这段程序里面的num不也是局部变量吗?为什么上面的代码却可以将值赋给temp并且成功打印呢?
其实这里的num就是局部变量,而且它也会被释放,但是它传回来的是一个值!!!是一个值!而我们上面的返回的是一个地址。地址代表了这个空间的地址,但是这个空间被释放了。当然不能再通过这个地址得到里面的数据,而值呢却是可以返回的。就像我们天天写的int main() return 0;这里的return 0;也是程序在执行结束以后给操作系统的一个返回值,代表程序正常终止。(值与地址的区别)这一点要注意。

知识总结补充:
栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量, 也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。


静态存储


静态存储是整个程序执行期间都存在的存储方式,使变量成为静态的方式有两种:

  1. 在函数外面定义它,全局变量
  2. 在声明是使用static关键字:如 static double fee = 56.50;
    如果我们将上面的代码改一下
    这里写图片描述
    这里写图片描述

我们会发现局部变量的声明周期将不再是函数结束就释放,因为由于static的修饰它已经不是一个存放在栈上的局部变量了,而是一个存放在全局数据区data段的静态已初始化的static静态变量。

我们再来看一下全局变量,当我们声明一个全局变量的时候,这个全局变量的生命周期就是直到整个程序运行结束之后才释放,而且程序内所有的函数都可以对它进行修改和访问,也就是因为这一点我们一般不提倡使用全局变量,一是因为它会占用存储空间在整个程序执行期间(举个生活中的例子,没有人会愿意在旅游出门的时候就把锅碗瓢盆甚至床都带着(全局变量),我们有钱就可以,要吃饭的时候买了吃了就扔了(局部变量)),而是每个地方都会不小心对它改变,可能会造成我们一想不到的后果(同样举个生活中的例子;一个班级的水桶,谁都可以去喝谁都可以去动,当然你也不知道会有人偷偷的动了手脚)。

知识总结补充:

  • 全局数据区的data段:存放初始化后的非const的全局变量变量或者局部static变量。
  • 全局数据区的bss段:存放未初始化后的非const全局变量和局部static变量。
  • 全局数据区的readonly段:是存放只读数据(常量)
  • common段是存放注释的

动态存储


new和delete操作符提供了一种比自动变量和静态变量更灵活的方法,它们管理了一个内存池,这在C++中被称为自由存储空间(free store)或者堆空间。内存池同用于静态变量和自动变量的内存是分开的。new和delete允许在一个函数中分配内存,而在另一个函数中释放它。因此,数据的生命周期就不完全受到程序或者函数的生存时间的控制了,与使用常规变量相比,使用new和delete使程序员对程序如何使用内存有更大的控制权。
将上面的程序再改一下:
这里写图片描述
这里写图片描述
程序执行正常,n被是手动在堆上分配了内存。它的生命周期在出现delete或者整个程序结束。


当然堆空间的便利也会带来一些问题:那就是“内存泄漏”。程序员对内存的控制权越大越容易发生这种问题。如果我们没有良好的编程习惯以及内存分配和使用不当就会经常出现内存泄漏,野指针等内存问题。即使是最好的程序员和软件公司,也可能遇到内存泄漏的问题。如何避免?最好的方法就是养成这样一种好的习惯。即同时使用new和delete操作符,在堆空间上动态分配内存使用结束之后就释放它,并且将delete释放的指针置为NULL;
再看一个例子
这里写图片描述
这里写图片描述
这里写图片描述
我们会发现。上面这个例子:虽然我恶狠狠的delete了结构体指针ps。但是却仍然可以使用ps。因为我们只是释放了ps所指向的内容,但是这个指针还是存在的,而且这样的失误会可能导致我们误用已经释放的指针(造成意想不到的后果)或者将已经释放的指针再次释放。
再次释放的后果:
这里写图片描述

所以我们应该养成好习惯在delete之后将指针置空,这样可以避免再次对该指针操作,或出错
这里写图片描述
如上置空指针NULL之后再次使用就会出错
这里写图片描述

知识总结补充
堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc。new等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free。delete等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减) 。

  • 不要使用delete来释放不是new分配的内存
  • 不要使用delete来释放同一块内存两次
  • 如果使用new[ ] 为数组分配内存,则应该使用delete[ ]来释放
  • 如果使用new 为一个实体分配内存,则应该使用delete 来释放
  • 使用完delete或free之后应该将指针置为空(NULL)
1 0