技术交流QQ群:1027579432,欢迎你的加入!

1.Cpp的变量作用域

  • 作用域是程序的一个区域,一般来说有三个地方可以定义变量:
    • 局部变量:在函数或一个代码块内部声明的变量
    • 形式参数:在函数参数的定义中声明的变量(稍后介绍)
    • 全局变量:在所有函数外部声明的变量

2.局部变量

  • 在函数或一个代码块内部声明的变量,称为局部变量,它只能被函数内部或代码块内部的语句使用。如下:
// 局部变量声明,没有为其分配内存空间
int main(){
    // 局部变量声明,没有为其分配内存空间
    int a, b;
    int c;
    // 实际初始化
    a = 10;
    b = 20;
    c = a + b;
    cout << "c = " << c << endl;

    return 0;
}

3.全局变量

  • 在所有函数外部定义的变量(通常在程序的开始处),称为全局变量。全局变量从定义处开始至程序结束起作用,即全局变量存在有效作用域,全局变量的值在程序的整个生命周期内都是有效的。全局变量可以被任何函数访问,即全局变量一旦声明,在整个程序中都是可以用的,如:
// 全局变量的声明
int g;

int main(){
    // 局部变量声明,没有为其分配内存空间
    int a, b;
    int c;
    // 实际初始化
    a = 10;
    b = 20;
    c = a + b;
    cout << "c = " << c << endl;

    return 0;
}

4.全局变量与局部变量同名的情况

  • 在程序中,局部变量与全局变量的名称可以相同,但在main函数内部时,局部变量的值会覆盖全局变量的值。但是在子函数内的局部变量与全局变量是两个独立的变量,互不影响,如:
//-----------------------------------------------------//
但是,在子函数内的局部变量与全局变量是两个独立的变量,互不影响
int func();  // 子函数声明

// 全局变量的声明
int g = 233;


int main(){
    // 局部变量声明,没有为其分配内存空间
    int a, b, kk;
    int c;
    // 实际初始化
    a = 10;
    b = 20;
    c = a + b;
    cout << "c = " << c << endl;
    // 全局变量与局部变量同名时,局部变量会覆盖全局变量的值
    int g = 666;
    cout << "g = " << g << endl;
//------------------------------------------------------------------------//
    // 在程序中,全局变量与局部变量的名称可以相同,但是在子函数内的局部变量与全局变量是两个独立的变量,互不影响
    kk = func();
    cout << "kk = " << kk << endl;
    return 0;
}
// 子函数定义
int func(){
    return g;
}

  • 在一个函数体内可以存在重名的变量,前提是它们的作用域不同,如下:
        int aa = 22;
        {
            int aa = 77;
            cout << "inner aa = " << aa << endl;
        }
        cout << "outer aa = " << aa << endl;
    
    • 分析:当变量间出现重名的情况下,作用域小的屏蔽作用域大的,所以上面第一个 cout 输出 aa 的值为77,但由于在块里面申请的变量作用域只限于当前块,所以离开这个块后变量会自动释放,所以第二个 cout 输出 aa 的值为22。
  • 全局变量的值可以在局部函数内重新赋值
// 全局变量声明
int g = 20;
int fun1(int a,int b){
    g=a+b;
    cout<<"被改变的全局变量为:"<<g<<endl;
    return 0;
}

int fun2(){
    cout<<"此时的全局变量为:"<<g<<endl;
    return 0;
}

int main(){
    fun2();
    fun1(10,20);
    fun2();
    return 0;
}
  • 若要想让 main 函数也使用全局变量 a,可以用 extern 对全局变量进行声明,就可以合法使用
#include<iostream>
using namespace std;

int main()
{
     extern int a;
     cout<<"a= "<<a<<endl; //合法,输出10
     return 0;
}
int a=10; //全局变量从此处定义

5.静态变量

  • 存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底 static 还是用来隐藏的,虽然这种用法不常见。
  • 如果作为 static 局部变量在函数内定义,它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。
#include <iostream>
using namespace std;

int count = 1; //全局变量

int fun()
{
    static int count = 10; // 在第一次进入这个函数的时候,变量 count 被初始化为 10!并接着自减 1,以后每次进入该函数,count 的值是上一次函数运行之后的值
    return count--;        // 就不会被再次初始化了,仅进行自减 1 的操作;在 static 发明前,要达到同样的功能,则只能使用全局变量
}
 
//int count = 1; //全局变量
 
int main()
{
     cout<<"global  "<<"local staic"<<endl;
     for(int i = 1; i <= 10; ++count)
        cout<< i <<"        "<< fun() <<endl;
     return 0;
}
  • 全局变量和和局部变量同名时,可通过域名在函数中引用到全局变量,不加域名解析则引用局部变量
#include<iostream>
using namespace std;

int a = 10;
int main()
{
    int a = 20;
    cout << ::a << endl;   // 10
    cout << a << endl;     // 20
    return 0;
}

6.初始化全局变量和局部变量

  • 当局部变量被定义时,系统不会对其初始化,必须自行初始化。定义全局变量时,系统会自动进行初始化。正确初始化变量是一个良好的编程习惯,否则有时候程序会产生意想不到的结果。全局变量自动初始化的值如下:


    全局变量自动初始化的值.png

7.Cpp中全局变量,局部变量,静态全局变量,静态局部变量对比

  • C++ 变量根据定义的位置的不同的生命周期,具有不同的作用域,作用域可分为6种:全局作用域,局部作用域,语句作用域,类作用域,命名空间作用域和文件作用域。
    • 7.1 从作用域来看:
      • 全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件,包含全局变量定义的源文件还需要用extern 关键字再次声明这个全局变量。
      • 静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。
      • 局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。
      • 静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。
    • 7.2 从分配内存空间来看:
      • 全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间。
      • 全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
      • 从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的,应予以注意。
      • Tips:
        • 若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
        • 若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
        • 设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
        • 如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数)
        • 函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
  • 静态全局变量:改变作用范围,不改变存储位置
  • 静态局部变量:改变存储位置,不改变作用范围
  • 静态函数 :在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。
  • 如果在一个源文件中定义的函数,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用,这种函数也称为内部函数。定义一个内部函数,只需在函数类型前再加一个“static”关键字即可。