【C++存储类】

C++(存储类)
摘抄链接
摘抄链接
摘抄链接

(💌作为自己的复习笔记)

作用域是从空间的角度来分析的,分为全局变量局部变量

变量另一种属性:存储期(storage duration,也称生命期)。
存储期是指变量在内存中的存在期间。这是从变量值存在的时间角度来分析的。
存储期分为:

  1. 静态存储期(static storage duration)
  2. 动态存储期(dynamic storage duration)

这是由变量的静态存储方式动态存储方式决定的。
🎨静态存储方式:指在程序运行期间,系统对变量分配固定的存储空间。
(程序开始执行时分配,在程序执行完毕时释放,在程序过程中它们占据国定的存储单元,而不是动态分配和释放)。
🎨动态存储方式:指在程序运行期间,系统对变量动态地分配存储空间。
(在程序过程中申请和释放的一些空间)

内存中的供用户使用的🎨存储空间分为三部分:

  1. 程序区
  2. 静态存储区
  3. 动态存储区

数据分别存放在静态存储区动态存储区中。
全局变量全部存放在静态存储区中:在程序开始执行时给全局变量分配存储单元,程序执行完毕就释放这些空间。在程序执行过程中它们占据固定的存储单元,而不是动态地进行分配和释放。

🎨动态存储区中存放以下数据:

  1. 函数形式参数。在调用函数时给形参分配存储空间。
  2. 函数中的自动变量(未加static声明的局部变量)。
  3. 函数调用时的现场保护和返回地址等。
    对以上这些数据,在函数调用开始时分配动态存储空间,函数结束时释放这些空间。在程序执行过程中,这种分配和释放是动态的,如果在一个程序中两次调用同一函数,则要进行两次分配和释放,而两次分配给此函数中局部变量的存储空间地址可能是不相同的。
    如果在一个程序中包含若干个函数,每个函数中的局部变量的存储期并不等于整个程序的执行周期,它只是整个程序执行周期的一部分。根据函数调用的情况,系统对局部变量动态地分配和释放存储空间。

C++变量和函数包括两个属性:数据类型和数据的存储类别
🎨存储类别:指的是数据在内存中存储的方法。
🎨存储方法分为:静态存储动态存储两大类。
具体包含4种:自动类型(auto)、静态类型(static)、寄存器类型(register)和外部类型(extern)。
自动类型、寄存器类型的变量属于动态变量
静态类型、外部类型的变量属于静态变量

🎈根据变量的 存储类别,可以知道变量的 作用域 和 存储期 。

在C++面向对象设计中,由于类具有封装性,所有类中的成员均不能使用extern,auto,register

1.🎨自动变量(auto)
用自动类型关键词auto说明的变量称为自动变量auto只能修饰局部变量,不能修饰全局变量。
特性自动变量动态局部变量,具有块作用域特点,存放在动态存储区。定义时可加auto说明符,也可以省略,所以在程序中没有进行特殊声明都默认是auto型变量。系统以栈(Stack)方式为auto变量分配内存空间,在变量作用域结束后,栈空间由系统进行自动回收。不进行默认初始化,如果自动变量在定义时未初始化,其值默认为随机数。

函数的形参和在函数中定义的变量(包括在复合语句中定义的变量)都属此类。在调用该函数时,系统给形参和函数中定义的变量分配存储空间,数据存储在动态存储区中。在函数调用结束时就自动释放这些空间。如果是在复合语句中定义的变量,则在变量定义时分配存储空间,在复合语句结束时自动释放空间。因此这类局部变量称为自动变量(auto variable)。自动变量用关键字auto作存储类别的声明。

void testAuto()
{
	//在c++中进行了优化,不能这样写   auto int i=0
	//它的自动在于,程序进入包含变量声明的代码块时,变量开始存在
	//当程序离开这个代码块,变量消失
	auto  i = 0;
	int j=0;//两者等效,我们一般习惯省去了auto
}

2、🎨寄存器变量(register)
用寄存器类型关键词register说明的变量称为寄存器变量register只能修饰局部变量,不能修饰全局变量。
寄存器变量是动态局部变量,具有局部作用域,存放在CPU的寄存器或动态存储区;这样可以提高存取速度,如果没有存放在通用寄存器中,便按自动变量处理。

void testRegister()
{
	//cpu如果需要使用某个数据多次,我们都知道cpu
	//从内存中读数据很慢。寄存器变量,变量存放到
	//寄存器中,可以大大的提到cpu读取数据的速度
	register int i = 0;
	for (i; i++; i < 100000)
	{
		//todo
	}
}

使用register变量应注意:

  1. 由于通用寄存器的数量有限,寄存器类型的变量不宜过多。
  2. 变量的长度应与通用寄存器的长度相当。一般为int型或者char型。通常需要把一些频繁使用的局部变量定义为寄存器变量。
  3. 在c++中register进行了优化,我们可以不声明一个变量为寄存器变量,但当我们可能需要使用其很多次,编译器会自动进行优化,将其升级为寄存器变量。(一般的编译器为用户考虑这个问题,一般不需要考虑)
  4. 在c语言中寄存器变量不可以取地址,因为其并不在内存中,但是在c++中当我们取地址时,编译器会自动将寄存器变量降为普通变量,既可以取地址。
  5. 寄存器变量不能定义为全局变量。

3、🎨静态变量(static)
用静态类型关键词static说明的变量称为静态变量
static可以修饰局部变量和全局变量。因此静态变量分为静态局部变量静态全局变量
被声明为静态变量类型的变量,无论是局部还是全局的,都存在数据区中,其生命周期是整个程序。区别在于访问权限不一样。
在C++中规定静态局部变量有默认值,默认值分别为int型等于0,float型等于0.0,char型为’\0’,静态全局变量也是如此。而自动类型和寄存器类型变量没有默认值,为随机数。
(1) 静态局部变量
定义在函数内的静态变量称为静态局部变量。特点如下:

  1. 静态局部变量本身也是局部变量,具有局部变量的作用域。其作用域局限在定义它的本函数体内,当离开该函数体后,不可使用该变量,但其值还继续保留。也就是说函数结束时,静态局部变量的存储空间不会被释放。
  2. 静态局部变量属于静态存储类别的变量,在程序运行开始就被分配固定的存储单元(占用静态存储区),整个程序运行期间不再被重新分配,生存期是整个程序的运行期间
  3. 静态局部变量的赋初值时间在编译阶段,且仅被初始化一次,并不是每发生一次函数调用就赋一次初值。当再次调用该函数时,静态局部变量会保留上次调用函数时的值
#include<iostream>
using namespace std;

void f() {
int x = 0;//x 是自动类型
static int y = 3;//y是局部静态类型
x = x + 1;
y = y + 1;
cout << x << '\t' << y << endl;
}
 
int main ()
{
int i;
for (i = 0; i < 3; i++)
f();
system("pause");
return 0;
}
//输出:   1 4        
//        1 5         
//        1 6
//分析:x是自动变量,每次调用结束时,变量x的存储单元被释放,然而y是是局部静态类型,静态局部变量的赋初值时间在编译阶段,且仅被初始化一次,并不是每发生一次函数调用就赋一次初值。
//当再次调用该函数时,静态局部变量会保留上次调用函数时的值。

静态局部变量的说明:
静态局部变量在静态存储区内分配存储单元。在程序整个运行期间都不释放。
而自动变量(即动态局部变量)属于动态存储类别,存储在动态存储区空间(而不是静态存储区空间),函数调用结束后即释放。
如果在定义静态局部变量时不赋初值的话,编译时会自动赋初值0或空字符‘\0’。而对自动变量来说,如果不赋初值,则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值是不确定的。
静态局部变量是在编译时赋初值的,所以只赋初值一次,在程序运行期间它已有初值,每次调用函数时不再重新赋值而是保留上次调用结束时的值。而自动变量是在函数调用时赋初值的,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的,也就是说,在其他函数中它是“不可见”的。
在什么情况下需要用局部静态变量呢?
1)需要保留函数上一次调用结束时的值。例如可以用下例中的方法求n!。
2)如果初始化后,变量只被引用而不改变其值,则这时用静态局部变量比较方便,以免每次调用时重新赋值。 但是应该看到,用静态存储要多占内存,而且降低了程序的可读性,当调用次数多时往往弄不清静态局部变量的当前值是什么。因此,如不必要,不要多用静态局部变量。

(2) 静态全局变量
在定义全局变量时加说明符static,称为静态全局变量。静态全局变量只能被定义它的源文件中的所有函数共享。而不能被其他源文件中的函数使用,如果希望全局变量在多个源文件中被使用,则需通过外部(extern)关键字来声明。静态全局变量的特点如下。

  1. 与全局变量基本相同,其作用域是定义它的程序文件中,而不是整个程序中的所有文件。
  2. 静态全局变量属于静态存储类别的变量,所以它在程序一开始运行时,就被分配有文件固定的存储单元,默认初始化为0。全局变量都是存放在静态存储区的,其生存期是整个程序运行期间。
  3. 使用静态全局变量的好处是同一程序的两个不同源程序文件中可以使用相同名。

4.🎨外部变量(extern)
用部类型extern说明的全局变量称为外部变量extern只能修饰全局变量。把全局变量在其他源文件中声明成 extern 变量,可以扩展该全局变 量的作用域至声明的那个文件,其本质作用就是对全局变量作用域的扩展。
定义格式为:extern 类型 变量名;
在由多个源程序文件组成的程序中,如果一个文件要使用另一个文件中定义的全局变量,这些源程序文件之问通过外部类型的变量进行沟通。

在一个文件中定义的全局变量默认为外部的,即作用域可以延伸到程序的其他文件中。但其他文件如果要使用这个文件中定义的全局变量,必须在使用前用extern作外部声明,外部声明通常放在文件的开头。

变量定义时编译器为其分配存储空间,而变量声明指明该全局变量已在其他地方说明过,编译系统不再分配存储空间,直接使用变量定义时所分配的空间。

//extern.cpp
#include<iostream>
int extern_vule = 8888;
//main.cpp
void testExtern()
{
	extern int extern_vule;
	extern_vule++;
	printf("%d\n", extern_vule);
}

注:
在extern.cpp中声明定义了 extern_vule,在main.cpp中想使用这个变量,我们需要声明extern int extern_vule;
但是不能再给这个变量赋值。
在extern.cpp中定义的extern_vule必须是全局变量才可以用extern,进而被其他文件访问到。

🦄C语言内存分配机制
(1)栈(Stack):位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效。
(2)堆(Heap):由程序员用malloc/calloc/realloc分配,free释放。如果程序员忘记free了,则会造成内存泄露,程序结束时该片内存会由OS回收,但程序只要不结束,就有可能造成内存泄露。(程序员负责分配和释放)
(3)全局区/静态区(Global Static Area): 全局变量和静态变量存放区,程序一经编译好,该区域便存在。并且在C语言中初始化的全局变量和静态变量和未初始化的放在相邻的两个区域(在C++中,由于全局变量和静态变量编译器会给这些变量自动初始化赋值,所以没有区分了)。由于全局变量一直占据内存空间且不易维护,推荐少用。程序结束时释放。
(4)C风格字符串常量存储区: 专门存放字符串常量的地方,程序结束时释放。
(5)程序代码区:存放程序二进制代码的区域。

🦄C++语言内存分配机制
在C++语言中,与C类似,不过也有所不同,内存主要分为如下5个存储区:
(1)栈(Stack):是分配给函数局部变量的存储单元。位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效。
(2)堆(Heap)由程序员用malloc/calloc/realloc分配,free释放的动态内存单元,与堆类似。如果程序员忘记free了,则会造成内存泄露,程序结束时该片内存会由OS回收。
(3)自由存储区(Free Storage)由new创建,由delete或delete[]释放的动态内存单元。如果用户不释放该内存,程序结束时,系统会自动回收。
(4)全局区/静态区(Global Static Area)全局变量和静态变量存放区(占一块内存空间),程序一经编译好,该区域便存在。在C++中,由于全局变量和静态变量编译器会给这些变量自动初始化赋值,所以没有区分了初始化变量和未初始化变量了。需要说明一点,全局静态变量和局部静态变量都是存储在同一个静态区(全局区),只是作用域不同。
(5)常量存储区: 这是一块比较特殊的存储区,专门存储 不能修改的常量(一般是const修饰的变量,或是一些常量字符串)。

从技术上来说,堆(heap)是C语言和操作系统的术语。堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,稍后调用free可把内存交还。而自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就区别于堆了。

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值