变量的存储属性与内存管理

来源:互联网 发布:gis矢量数据融合 编辑:程序博客网 时间:2024/05/17 04:10

一、变量存储属性

变量是对程序中数据的存储空间的抽象。因此变量的属性包含两个:数据类型和存储类型

1、数据类型

数据类型决定了数据所占存储空间的大小及取值范围

2、存储类型

存储类型决定了变量的作用域和生存期

存储类型包括4种:自动型(auto)、寄存器型(register)、静态型(static)和外部型(extern)这四种

存储类型有两种存储方法:静态存储和动态存储。其中auto和register为动态存储,static和extern为静态存储。

2.1 自动变量(auto)

自动变量也叫局部变量(在函数或类内部定义的变量),是指在函数内部说明的变量。所有的非全局变量都被

认为是局部变 量,所以auto实际上从来不用。局部变量在函数调用时自动产生,但不会自动初始化, 随函数

调用的结束,变量自动消失,下 次调用此函数时再自动产生,还要重新赋值,退出时又自动消失。

作用域:从函数定义开始,到函数体或复合体结束。

2.2 寄存器变量(register)

寄存器变量也是自动变量,只有局部比变量、形参可以定义为register,静态变量(全局变量肯定是静态变量)

不能定义为register。一般的变量都是存储在内存中的,在程序需要的时候,就把变量从内存中读取到运算器中。

比较关注速度时,可以使用register将变量存在操作比内存快的寄存器中。值得注意的是,取地址运算符&不

能作用于寄存器。  

作用域:从函数定义开始,到函数体或复合体结束。

2.3 静态变量(static)

静态变量的生命周期是整个程序的一次执行过程,即值会一直保持不变(生命周期长)。但是作用范围是被限

的。即静态全局变量不能被定义静态全局变量的文件之外的其他文件所引用;静态局部变量不能在函数外使用。

(1)静态局部变量  
它与局部变量的区别在于:在函数退出时,这个变量始终存在,只是不能被其它函数使
用,当再次进入该函数时,

将保存上次的结果。其它与局部变量一样。 

(2)静态全局变量 
静态全局变量就是指只在定义它的源文件中可见而在其它源文件中不可见的变量。它
与全局变量的区别是:全

变量可以再说明为外部变量(extern),被其它源文件使用,而静态全局变量不能再被说明为外部的,即只能被所在

源文件使用。

2.4 外部变量(extern)

在函数之外定义的变量称为全局变量或外部变量。作用域为从定义变量开始到源文件结束。编译时会将全局变

量分配在静态存储区。

全局变量在下面两种情况下需要使用extern声明:

(1)在同一个文件中,若全局变量定义在后而使用在前时,则需要在使用之前使用extern对该变量进行外部变

量声明。

(2)若多个文件的程序要引用同一个全局变量,好的做法是:在一个文件中定义外部变量,而在非定义的文件

中使用extern对该变量作外部变量声明。


二、内存管理

内存分配方式有三种:


(1)从静态(全局)存储区域

内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,生命周期长。例如全局变量,

static变量。

int a1;   //初始化为0char s1;   //初始化为0static int a2;   //初始化为0static char s2;   //初始化为0void fun_test(int par){static int a3;   //初始化为0static char s3;   //初始化为0int a4;   //未初始化char s4;   //未初始化char *ptr = new char[10];delete []ptr; ptr = 0;char *ss = "123456789";}

e.g..

全局变量a1、s1,静态全局变量a2、s2,静态局部变量a3、s3,默认初始化为0;还有字符串常量“123456789”

值得注意的是静态局部变量a3、s3的作用范围为函数fun_test内;字符串常量占据的空间是10字节(末尾有‘\0’)。


(2)栈

在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈

内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

e.g..

形参par,局部变量(自动变量)a4、s4,指针ptr、ss。均不会自动初始化。


(3) 堆,亦称动态内存分配

程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动

态内存的生存期由我们决定,使用非常灵活,但问题也最多。只有在堆上分配的内存才需要(也必须)我们进

行释放,否则就会造成内存泄漏。

e.g..

new分配的10字节内存(ss指向的内存区域)。

三、malloc和new的区别

1 malloc和free是C++/C的标准库函数,new和delete是C++的运算符。C++程序经常要调用C函数,而C程序只能调用malloc和new函数。

2 对于非内部类型的对象而言,malloc和free无法满足动态对象的要求。

由于malloc和free是库函数不是运算符,不在编译器控制权限之内,无法在对象创建时调用构造函数,在对象消亡前自动调用析构函数;

而new是运算符,能动态完成内存分配和初始化的工作;delete运算符能够完成清理和释放内存的工作。

3 malloc和free,以及new和delete的使用

3.1 malloc()、free()函数。int*p;p=(int*)malloc(sizeof(int)*128); ... free(p);p=NULL;

3.1.1原型:extern void *malloc(unsigned int num_bytes);  e.g.. char *ptr; ptr = (char*)malloc(100);   ...   free(p);p=NULL;

说明:分配长度为num_bytes字节的内存块。如果分配成功则返回指向被分配内存的指针,分配失败返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。备注:void* 表示未确定类型的指针,更明确的说是指申请内存空间时还不知道用户是用这段空间来存储什么类型的数据(比如是char还是int或者...)。虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一些编译器的检查。

3.1.2 malloc()到底从哪里得到了内存空间?
答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。

3.2 new、delete运算符。int* parr;parr=new int[100];   ...   //delete []parr; parr=0;

一旦删除了指针所指的对象,立即将指针置为0,这样就非常清楚的指明指针不再指向任何对象。(零值指针:int *ip=0;)

3.2.1 int *pi=new int; 这个new表达式在堆区中分配创建了一个整型对象,并返回此对象的地址,并用该地址初始化指针pi 。

3.2.2 撤销动态创建的对象。delete pi;//释放单个对象   delete[]pi;//释放数组

3.3 区分零值指针和NULL指针
零值指针,是值是0的指针,可以是任何一种指针类型,可以是通用变体类型void*也可以是char*,int*等等。
空指针,其实空指针只是一种编程概念,就如一个容器可能有空和非空两种基本状态,而在非空时可能里面存储了一个数值是0,因此空指针是人为认为的指针不提供任何地址讯息。

4 new返回指定类型的指针,并且可以自动计算所需大小;而malloc则必须由我们计算字节数,并且在返回后强制转为实际类型的指针

5 new失败时抛出std::bad_alloc异常;malloc分配失败时返回空指针NULL。

2 0
原创粉丝点击