C++学习笔记:变量属性

C++学习笔记:变量属性,第1张

C++学习笔记:变量属性 前言

好久没用c++了,把书上的一些内容搬过来,方便以后自己查看

1.变量的作用域(从空间的角度–全局与局部) 1.1 如果在同一个源文件中,全局变量与局部变量同名,则在局部变量的作用范围内,全局变量被屏蔽,即它不起作用。变量的有效范围称为变量的作用域(scope)。归纳起来,变量有4种不同的作用域:(在此作用域下才能使用变量)
    文件作用域函数作用域块作用域函数原型作用域

文件作用域是全局的,其他三者是局部的。

2.变量的存储类别 2.1 动态存储方式与静态存储方式(从时间的角度,存储方式决定生命周期)

存储期(storage duration), 也称生命周期,是指变量在内存中的存在期间。

存储期可以分为静态存储期(static storage duration) 和 (dynamic storage duration)。这是由变量的静态存储方式和动态存储方式决定的。

静态存储方式是指程序运行期间,系统对变量分配固定的存储空间。

动态存储方式则是在程序运行期间,系统对变量动态地分配存储空间。

内存中地供用户使用的存储空间可以分为三部分。即:

(1)程序区

(2)静态存储区

(3)动态存储区

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

在动态存储区中存放以下数据:1.函数形式参数。在调用函数时给形参分配存储空间。2.函数中的自动变量(未加static声明的局部变量,详见后面的介绍)。3.函数调用时的现场保护和返回地址等。

在C++中变量除了有数据类型的属性之外,还有存储类别(storage class) 的属性。存储类别指的是数据在内存中存储的方法。存储方法分为静态存储和动态存储两大类。具体包含4种:自动的(auto)、静态的(static)、寄存器的(register)和外部的(extern)。根据变量的存储类别,可以知道变量的作用域和存储期。

下面分别作介绍。

2.2 自动变量(自动分配空间,自动释放空间)

函数中的局部变量,如果不用关键字static 加以声明,编译系统对它们时动态地分配存储空间的。在调用该函数时,系统给形参和函数中定义的变量分配存储空间,数据存储在动态存储区中。在函数调用结束时就自动释放这些空间。如果是在复合语句中定义的变量,则在变量定义时分配空间,在复合语句结束时自动释放空间。这类称为自动变量。自动变量用关键字auto作存储类别的声明。

int f(int a)
{
    //C++变量中除了数据类型的属性之外,还有存储类别的属性。
    auto int b, c =3;//存储类别auto和数据类型int的顺序任意
}

关键字auto可以省略,如果不写auto,则系统把它默认为自动存储类别,它属于动态存储方式。程序中大多变量属于自动变量。

2.3 用static声明静态局部变量(静态:存储方式,局部:作用域)

有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在下一次该函数调用时,该变量保留上一次函数调用结束时的值。这时就应该指定局部变量为静态局部变量:

例子 静态局部变量的值:

#include
using namspace std;
int f(int a)
{
    int b = 0; //不声明为static,函数作用域下的变量为动态存储方式
    static int c = 3;//但是有时希望函数里的变量变为静态存储,这时声明为static
    b = b + 1;
    c = c + 1;
    return a + b +c;
}
int main()
{
    int a = 2, i;
    for (i =0; i< 3;i++)
        cout< 

对静态变量的说明:

(1) 静态局部变量在静态存储区内分配存储单元。在程序整个运行期间不释放。而自动变量(即动态局部变量)属于动态存储类别,存储在动态存储区空间(而不是静态存储区空间),函数调用结束后即释放。

(2) 为静态局部变量赋初始值实在编译时进行赋值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不在重新赋初始值而只是保留上次函数调用结束时的值。而为自动变量赋初值,不是在编译时进行的,而是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。

(3) 如果在定义局部变量时不赋初值的话,对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符型变量)。而对自动变量来说,如果不赋初值,则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值是不确定的。

(4) 虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的,也就是说,在其他函数中它是“不可见”的。(存储类别和作用域)

在什么情况下需要用局部静态变量呢?

(1)需要保留函数上一次调用结束时的值。

(2)如果初始化后,变量只被引用而不改变其值,则这时用静态局部变量比较方便,以免每次调用时重新赋值。

用静态存储要多占内存,而且降低了程序的可读性,当调用次数多时往往弄不清楚静态局部变量时的当前值是什么。因此,如不必要,不要多用静态局部变量。

2.4 用register声明寄存器变量
int fac(int n)
{
    register int i, f=1;
    for(i=1;i<=n;i++) f = f*i;
    return f;
}
2.5 用extern声明外部变量

全局变量(外部变量)是在函数的外部定义的,它的作用域为从变量的定义处开始,到本程序文件的末尾。在此作用域内,全局变量可以为本文件中各个函数所引用。编译时将全局变量分配在静态存储区。

有时需要用extern来声明全局变量,以扩展全局变量的作用域。

1.在一个文件内声明全局变量

如果在定义点之前的函数想引用全局变量,则应该在引用之前用关键字extern对该变量作外部变量声明,表示该变量是一个将在下面定义的全局变量。有了此声明,就可以从声明处起,合法地引用该全局变量,这种声明称为提前引用声明。

#include
using namespace std;
int max(int, int);
void main()
{
    extern int a,b;   //提前引用声明
    cout<< max(a, b)<y?x:y;
    return z;
}
//一般都把全局变量地定义放在引用它地所有函数之前,这样可以在避免在函数中多家一个extern声明。
2.在多文件的程序中声明外部变量

如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量num,不能分别在两个文件中各自定义一个外部变量num,否则在进行程序的连接时会出现“重复定义”的错误。正确的做法是:在任一个文件中定义外部变量num,而在另一文件中用extern对num作外部变量声明。即

extern int num;
2.6 用static声明静态外部变量

有时在程序设计中希望某些外部变量只限于被本文件引用,而不能被其他文件引用。这时可以在定义外部变量时加一个static声明。这种加上static声明、只能用于本文件的外部变量(全局变量)称为静态外部变量。

在程序设计中,常由若干人分别完成各个模块,各人可以独立地在其设计的文件中使用相同的全局变量名而互不相干。只需在每个文件中的全局变量前加上static即可。

需要指出,不要误认为用static声明的外部变量才采用静态存储方式,而不加static的是动态存储。实际上,两种形式的外部变量都用静态存储方式,只是作用范围不同而已,都是在编译时分配内存的。

3.变量属性小结

从前面的介绍中可以知道,一个变量除了数据类型以外,还有3中属性:

(1)存储类别 C++允许使用auto,static,register和extern 4中存储类别。

(2)作用域 指程序中可以引用该变量的区域。

(3)存储期 指变量在内存的存储期限。

以上3种属性都是有联系的,程序设计者只能声明变量的存储类别,通过存储类别可以确定变量的作用域和存储期。(存储类别 => 作用域和存储期)

下面从不同角度分析它们之间的联系。

(1)从作用域角度分,有局部变量和全局变量。它们采用的存储类别如下:

局部变量全局变量自动变量,即动态局部变量(离开函数,值就消失)
静态局部变量(离开函数,值仍保留)
寄存器变量(离开函数,值就消失)
形式参数(可以定义为自动变量或寄存器变量)静态外部变量(只限本文件引用)
外部变量(即非静态的外部变量,允许其他文件引用)

(2) 从变量存储期(存在的时间)来区分,有动态存储和静态存储两种类型。静态存储是程序整个运行时间都存在,而动态存储则是在调用函数时临时分配单元。

动态存储静态存储自动变量(本函数内有效)
寄存器变量(本函数内有效)
形式参数静态局部变量(函数内有效)
静态外部变量(本文件内有效)
外部变量(其他文件可引用)

(3)从变量值存放的位置来区分,可分为:

内存中静态存储区内存中动态存储区静态局部变量
静态外部变量(函数外部静态变量)
外部变量(可为其他文件引用)自动变量和形式参数 4. 常对象、常对象成员(const) 4.1 常对象
Time const t1(12, 34, 46);
const Time t1(12, 34, 46);//等价

void get_time() const; //将函数声明为const
mutable int count;//把count 声明为可变的数据成员,这样就可以用声明为const的成员函数来修改它

如果一个对象被声明为常对象,则不能调用该对象的非const型的成员函数。

有时希望一定要修改常对象中的某个数据成员的值(例如类中有一个用于计数的变量count,其值应当能不断变化),ANSI C++ 考虑到实际编程时的需要,对此做了特殊的处理,对该数据成员声明为mutable。

4.2 常对象成员

常数据成员的值是不能改变的。只能通过构造函数的参数初始化表对常数据成员进行初始化。只能通过构造函数的参数初始化表对常数据成员进行初始化。

Time::Time(int):hour(h){}
Time::Time(int h){hour=h;}//非法
5. 静态数据成员(static)

静态数据成员是一种特殊的数据成员。它以关键字static开头。例如,

class Box
{
    public:
    	int volume();
	private:
    	static int height;
    	int width;
    	int length;
};
5.1说明(1)

如果只声明了类而未定义对象,则类的一般数据成员是占内存空间的,只有在定义对象时,才为对象的数据成员分配空间。但是静态数据成员不属于某一个对象,在为对象所分配的空间中不包括静态数据成员,即使不定义对象,也为静态数据成员分配空间,它可以被引用。

在一个类中可以有一个或多个静态数据成员,所有的对象共享这些静态数据成员,都可以引用它。

5.2 说明(2)

如果在一个函数中定义了静态变量,在函数结束时该静态变量并不释放,仍然存在并保留其值。现在讨论的静态数据成员也是累死的,它不随对象的简历而分配空间,也不随对象的撤销而释放。静态数据成员时在程序编译时被分配空间的,到程序结束时才释放空间。

5.3 说明(3)

静态数据成员可以初始化,但只能在类体外进行初始化。例如:

int Box::height=10;//不必在初始化语句中加static。

不能用参数初始化表对静态数据成员初始化,如果未对静态数据成员赋初值,则编译系统会自动赋予初值0。

5.4 说明(4)

静态数据成员既可以通过对象名引用,也可以通过类名来引用。如果静态数据成员被定义为私有的,则不能在类外直接引用,而必须通过公用的成员函数引用。

5.5 说明(5)

有了静态数据成员,各对象之间的数据有了沟通的渠道,实现数据共享,因此可以不使用全局变量。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5702349.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存