C++学习日记 --C++变量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010170012/article/details/18891623

-.1 C++全局变量、局部变量和静态局部变量

我们已经在前面学习了变量,并且能够熟练的使用它。可是,仅仅靠这些知识,有些问题仍然无法得到解决。

标识符
首先要来介绍一下什么是标识符。在程序设计的过程中,经常要给变量、函数甚至是一些数据类型起名字(还包括以后的类名,对象名等)。我们把这些用户根据一些规定,自己定义的各种名字统称为标识符(identifier)。显然,标识符不允许和任何保留字相同。

全局变量和局部变量
我们说过函数体内声明的变量仅在该函数体内有效,别的函数是无法使用的。并且在函数运行结束后,这些变量也将消失了。我们把这些在函数体内声明的变量称为局部变量(Local Variable)。

然而,可能会遇到这样的问题:我们想要创建一个变量作为数据缓冲区(Buffer),分别供数据生成、数据处理和数据输出三个函数使用,三个函数都要能够读取或修改这个变量的值。显然通过传递参数或返回值来解决这个问题是非常麻烦的。

那么,我们能否建立一个变量能够让这三个函数共同使用呢?在C++中,我们可以在函数体外声明一个变量,它称为全局变量(global variable)。所为全局,是指对于所有函数都能够使用。当然,在该变量声明之前出现的函数是不知道该变量的存在的,于是也就无法使用它了。另外,如果我们声明了一个全局变量之后没有对它进行初始化操作,则编译器会自动将它的值初始化为0。

下面,我们就用全局变量来实现刚才提出的问题:
e.g.1:
#include "iostream.h"
#include "stdlib.h"//用于产生随机数
#include "time.h"//用于产生随机数
#include "iomanip.h"//用于设置域宽
void makenum();
void output();
void cal();
int main()
{
    srand(time(NULL));//用于产生随机数
    for(int i=0;i<4;i++)
    {
        makenum();//产生随机数放入缓冲区
        cal();//对缓冲区的数据进行处理
        output();//输出缓冲区的数值
    }
    return 0;
}
int buffer;//定义全局变量,以下函数都能使用它
void makenum()
{
    cout<<"Running make number..."<<endl;
    buffer = rand();//把产生的随机数放入缓冲区
}
void cal()
{
    cout<<"Runnning calculate..."<<endl;
    buffer = buffer % 100;
}
void output()
{
    cout<<"Runnning output..."<<endl;
    cout<<setw(2)<<buffer<<endl;
}

运行结果:
Running make number...
Running calculate...
Running output...
48
Running make number...
Running calculate...
Running output...
47
Running make number...
Runnning calculate...
Running output...
24
Running make number...
Running calculate...
Running output...
90
以上为某次运行得到的随机结果。可见,使用全局变量使得多个函数之间可以共享一个数据,同时从理论上实现了函数之间的通讯。

静态局部变量
全局变量实现了函数之间的共享数据,也使得变量不再会因为某个函数的结束而消亡。但是,新问题又出现了:一个密码检测函数根据调用(用户输错密码)的次数来限制他进入系统。如果把调用次数存放在一个局部变量里,显然是不可行的。虽然全局变量可以记录一个函数的运行次数,但是这个变量是被所有函数共享的,每个函数都能修改它,实在很危险。我们现在需要的是一个函数运行结束后不会消失的,并且其它函数无法访问的变量。

C++中,我们可以在函数体内声明一个静态局部变量(static local variable)。它在函数运行结束后不会消失,并且只有声明它的函数中能够使用它。声明一个静态局部变量的方法是在声明局部变量前加上static,例如:
static int a;
和全局变量类似,如果我们没有对一个静态局部变量做初始化,则编译器会自动将它初始化为0.

下面,我们就用静态局部变量来模拟一下这个密码检测函数的功能:
e.g.2:
#include "iostream.h"
#include "stdlib.h"
bool password();//密码检测函数功能
int main()
{
    do
    {

    }
    while(password()!=true);//反复检测密码知道密码正确
    cout<<"欢迎您进入系统!"<<endl;
    return 0;
}
bool password()
{
    static numOfRun = 0;//声明静态局部变量存放函数调用次数
    if(numOfRun < 3)
    {
        int psw;
        cout<<"第"<<++numOfRun<<"次输入密码"<<endl;
        cin>>psw;
        if(psw==123456)
        {
            return true;
        }
        else
        {
            cout<<"密码错误!"<<endl;
            return false;
        }
    }
    else
    {
        cout<<"您已经输入错密码三次!异常退出!"<<endl;
        exit(0);//退出程序运行
    }
}
第一次运行结果:
第1次输入密码
111111
密码错误!
第2次输入密码
222222
密码错误!
第3次输入密码
0
您已经输入错密码三次!异常退出!

第二次运行结果:
第1次输入密码
000000
密码错误!
第2次输入密码
123456
欢迎您进入系统!

使用静态局部变量可以让函数产生的数据更长期更安全的存储。如果一个函数运行和他以前的运行结果有关,那么一般我们就会使用静态局部变量。

-.2 C++变量的作用域
在程序的不同位置,可能会声明各种不同类型(这里指静态或非静态)的变量。然而,声明的位置不同、类型不同导致每个变量在程序中可以被使用的范围不同。我们把变量在程序中可以使用的有效范围称为变量的作用域。

任何变量都必须在声明之后才能被使用,所以一切变量的作用域都始于变量的声明之处。那么,他到什么地方终止呢?我们知道C++的程序是一个嵌套的层次结构,即语句块里面还能有语句块。最终语句块由各条语句组成,而语句就是程序中的最内层,是组成程序的一个最小语法单位。在某一层次声明的变量的作用域就终止于该变量所在层次的末尾。

举个例子来说明:
#include "iostream.h"
int main()
{
    int a = 3,b = 4;//变量a和b的作用域开始
    for(int i=0;i<5;i++)//在for语句内声明的变量i的作用域开始
    {
        int result = i;//变量result的作用域开始
        if(int j = 3)//在if语句内声明的变量j的作用域开始
        {
            int temp = 8;//变量temp的作用域开始
            result = temp+(a++)-(b--);
        }//变量temp的作用域结束
        else
        {
            result = 2;//if...else...语句结束,变量j的作用域结束
        }
        cout<<result<<endl;
    }//for语句结束,变量i和result的作用域结束
    return 0;
}//变量a和b的作用域结束

根据上面这段程序,我们发现每当一个语句块或语句结束,那么在该语句块或语句层次内声明变量的作用域也就结束了。所以,下面的这段程序就存在错误:
#include "iostream.h"
int main()
{
    int a=3,b=4;
    for(int i=0;i<5;i++)
    {
        int result=i;
        if(int j=3)
        {
            int temp=8;
            result=temp+(a++)-(b--);
        }
        else
        {
            result =2;
        }
        cout<<j<<result<<endl;//j的作用域结束,变量未定义
    }
    cout<<result<<endl;//result的作用域结束,变量未定义
    cout<<i<<endl;//这里居然是正确的,why?
    return 0;
}
变量j和result无法输出是在意料之中的,但是为什么明明变量i的作用域已经结束了,却还是能够正常输出呢?这是微软给我们开的一个玩笑。根据ANSI C++的标准,在for语句头中声明的变量的作用域的确应该在for语句的末尾结束。然而VC++却没有完全符合这个标准,他认为for语句头中声明的变量的作用域到包含该for语句的最小语句块结束。尽管如此,我们还是应该按照ANSI C++标准来认知变量的作用域。

-.3 C++变量的可见性
我们之前介绍过,在某一个函数中,不应该有两个名字相同的变量。可是,我们拿下面这段代码去测试一下,发现居然在同一个函数中可以有两个名字相同的变量。这又是怎么回事呢?编译器又是如何辨别这两个名字相同的变量的呢?
#include "iostream.h"
int main()
{
    int a=3,b=4;
    {
        int a=5,b=6;
        {
            char a='a',b='b';
            cout<<a<<b<<endl;
        }
        cout<<a<<b<<endl;
    }
    cout<<a<<b<<endl;
    return 0;
}

运行结果:
ab
56
34

我们已经说明,变量可以使用的范围是由变量的作用域决定。不同层次的变量的作用域,就好像大小不一的纸片。把它们堆叠起来,就会发生部分纸片被遮盖的情况。我们把这种变量作用域的遮盖情况称为变量的可见性(visibility)。


编译器正是根据变量的可见性,来判断我们到底引用哪个变量的。具体在程序中就是:
#include "iostream.h"
int main()
{
    int a=3,b=4;//整型变量a=3、b=4的作用域开始
    {
        int a=5,b=6;//整型变量a=5,b=6的作用域开始,整型变量a=3,b=4不可见
        {
            char a='a',b='b';//字符变量a='a',b='b'作用域开始,整型变量a,b不可见
            cout<<a<<b<<endl;//输出字符型变量,整型变量a,b不可见
        }//字符型变量a='a',b='b'作用域结束
        cout<<a<<b<<endl;//输出整型变量a=5,b=6,整型变量a=3,b=4不可见
    }//整型变量a=5,b=6作用域结束
    cout<<a<<b<<endl;//输出整型变量a=3,b=4
    return 0;
}//整型变量a=3,b=4的作用域结束

然而,当两张纸处于同一层次,显然两个就不可能发生遮盖了。所以如果我们在同一层次中声明了两个名字相同的变量,那么他们的作用域就不是遮盖,而是冲突了。

因此,在某个函数的同一语法层次内不能声明多个名字相同的变量。
 

猜你喜欢

转载自blog.csdn.net/u010170012/article/details/18891623