C变量类型和做用域

C语言中全部变量都有本身的做用域,申明变量的类型不一样,其做用域也不一样。C语言中的变量,按照做用域的范围可分为两种, 即局部变量和全局变量。 数组

1、局部变量

局部变量也称为内部变量。局部变量是在函数内做定义说明的。其做用域仅限于函数内, 离开该函数后再使用这种变量是非法的。模块化

例如:函数

int f1(int a) /*函数f1*/ 

    int b,c;spa

……
}设计

int f2(int x) /*函数f2*/ 

    int y,z;;对象

……
}blog

f1内定义了三个变量,a为形参,b,c为通常变量。在 f1的范围内a,b,c有效,或者说a,b,c变量的做用域限于f1内。内存

f2内定义了三个变量,x为形参,y,z为通常变量。在 f2的范围内x,y,z有效,或者说x,y,z变量的做用域限于f2内。ci

关于局部变量的做用域还要说明如下几点:作用域

         主函数中定义的变量也只能在主函数中使用,不能在其它函数中使用。同时,主函数中也不能使用其它函数中定义的变量。由于主函数也是一个函数,它与其它函数是平行关系。

         形参变量是属于被调函数的局部变量,实参变量是属于主调函数的局部变量。

         容许在不一样的函数中使用相同的变量名,它们表明不一样的对象,分配不一样的单元,互不干扰,也不会发生混淆。虽然容许在不一样的函数中使用相同的变量名,可是为了使程序明了易懂,不提倡在不一样的函数中使用相同的变量名。

2、全局变量

int a,b; /*外部变量*/ 
void f1() /*函数f1*/ 

…… 
}

float x,y; /*外部变量*/ 
int fz() /*函数fz*/ 

…… 
}

全局变量也称为外部变量,它是在函数外部定义的变量。 它不属于哪个函数,它属于一个源程序文件。其做用域是整个源程序。在函数中使用全局变量,通常应做全局变量说明。 只有在函数内通过说明的全局变量才能使用。全局变量的说明符为extern。 但在一个函数以前定义的全局变量,在该函数内使用可再也不加以说明。 例如: 
  从上例能够看出a、b、x、y 都是在函数外部定义的外部变量,都是全局变量。
  对于全局变量还有如下几点说明:

         对于局部变量的定义和说明,能够不加区分。而对于外部变量则否则,外部变量的定义和外部变量的说明并非一回事。外部变量定义必须在全部的函数以外,且只能定义一次。其通常形式为: [extern] 类型说明符 变量名,变量名… 其中方括号内的extern能够省去不写。 
   例如: int a,b; 
   等效于: 
 extern int a,b; 

   而外部变量说明出如今要使用该外部变量的各个函数内,在整个程序内,可能出现屡次,外部变量说明的通常形式为: extern 类型说明符 变量名,变量名,…; 外部变量在定义时就已分配了内存单元,外部变量定义可做初始赋值,外部变量说明不能再赋初始值,只是代表在函数内要使用某外部变量。

         外部变量可增强函数模块之间的数据联系,可是又使函数要依赖这些变量,于是使得函数的独立性下降。从模块化程序设计的观点来看这是不利的, 所以在没必要要时尽可能不要使用全局变量。

         在同一源文件中,容许全局变量和局部变量同名。在局部变量的做用域内,全局变量不起做用。 

int vs(int l,int w) 
{ 
extern int h; 
int v; 
v=l*w*h; 
return v; 
} 
main() 
{ 
extern int w,h; 
int l=5; 
printf("v=%d",vs(l,w)); 
} 
int l=3,w=4,h=5; 

   本例程序中,外部变量在最后定义, 所以在前面函数中对要用的外部变量必须进行说明。外部变量l,w和vs函数的形参l,w同名。外部变量都做了初始赋值,mian函数中也对l做了初始化赋值。执行程序时,在printf语句中调用vs函数,实参l的值应为main中定义的l值,等于5,外部变量l在main内不起做用;实参w的值为外部变量w的值为4,进入vs后这两个值传送给形参l,wvs函数中使用的h 为外部变量,其值为5,所以v的计算结果为100,返回主函数后输出。

变量的存储类型决定了各类变量的做用域不一样。所谓存储类型是指变量占用内存空间的方式,也称为存储方式。变量的存储方式可分为“静态存储”和“动态存储”两种。 
   静态存储变量一般是在变量定义时就分定存储单元并一直保持不变, 直至整个程序结束。动态存储变量是在程序执行过程当中,使用它时才分配存储单元, 使用完毕当即释放。 典型的例子是函数的形式参数,在函数定义时并不给形参分配存储单元,只是在函数被调用时,才予以分配, 调用函数完毕当即释放。若是一个函数被屡次调用,则反复地分配、 释放形参变量的存储单元。从以上分析可知, 静态存储变量是一直存在的, 而动态存储变量则时而存在时而消失。咱们又把这种因为变量存储方式不一样而产生的特性称变量的生存期。 生存期表示了变量存在的时间。 生存期和做用域是从时间和空间这两个不一样的角度来描述变量的特性,这二者既有联系,又有区别。 一个变量究竟属于哪种存储方式, 并不能仅从其做用域来判断,还应有明确的存储类型说明。

在C语言中,对变量的存储类型说明有如下四种:

  auto     自动变量 
  register    寄存器变量 
  extern    外部变量 
  static    静态变量 
   自动变量和寄存器变量属于动态存储方式,外部变量和静态变量属于静态存储方式。在介绍了变量的存储类型以后, 能够知道对一个变量的说明不只应说明其数据类型,还应说明其存储类型。所以变量说明的完整形式应为: 存储类型说明符 数据类型说明符 变量名,变量名…; 例如: 
   static int a,b;           说明a,b为静态类型变量 
   auto char c1,c2;          说明c1,c2为自动字符变量 
   static int a[5]={1,2,3,4,5};    说明a为静整型数组 
   extern int x,y;           说明x,y为外部整型变量 

   下面分别介绍以上四种存储类型: 
   1、自动变量的类型说明符为auto 
   这种存储类型是C语言程序中使用最普遍的一种类型。C语言规定, 函数内凡未加存储类型说明的变量均视为自动变量, 也就是说自动变量可省去说明符auto。 在前面各章的程序中所定义的变量凡未加存储类型说明符的都是自动变量。例如: 

{  int i,j,k; 
char c; 
…… 
}等价于: 

{ auto int i,j,k; 
auto char c; 
…… 

   自动变量具备如下特色: 
   1. 自动变量的做用域仅限于定义该变量的个体内。在函数中定义的自动变量,只在该函数内有效。在复合语句中定义的自动变量只在该复合语句中有效。 例如: 

int kv(int a) 
{ 
  auto int x,y; 
{  auto char c; 
} /*c的做用域*/ 
…… 
} /*a,x,y的做用域*/ 

   2. 自动变量属于动态存储方式,只有在使用它,即定义该变量的函数被调用时才给它分配存储单元,开始它的生存期。函数调用结束,释放存储单元,结束生存期。所以函数调用结束以后,自动变量的值不能保留。在复合语句中定义的自动变量,在退出复合语句后也不能再使用,不然将引发错误。例如如下程序: 

main() 
{ 
    auto int a,s,p; 
    printf("/ninput a number:/n"); 
    scanf("%d",&a); 
    if(a>0){ 
        s=a+a; 
        p=a*a; 
    } 
    printf("s=%d p=%d/n",s,p); 
} 
{ 
    auto int a; 
    printf("/ninput a number:/n"); 
    scanf("%d",&a); 
    if(a>0){ 
        auto int s,p; 
        s=a+a; 
        p=a*a; 
    } 
    printf("s=%d p=%d/n",s,p); 
}                         

   s,p是在复合语句内定义的自动变量,只能在该复合语句内有效。而程序的第9行倒是退出复合语句以后用printf语句输出s,p的值,这显然会引发错误。 
   3. 因为自动变量的做用域和生存期都局限于定义它的个体内( 函数或复合语句内), 所以不一样的个体中容许使用同名的变量而不会混淆。 即便在函数内定义的自动变量也可与该函数内部的复合语句中定义的自动变量同名。例5.14代表了这种状况。 

main() 
{ 
    auto int a,s=100,p=100; 
    printf("/ninput a number:/n"); 
    scanf("%d",&a); 
    if(a>0) 
    { 
        auto int s,p; 
        s=a+a; 
        p=a*a; 
        printf("s=%d p=%d/n",s,p); 
    } 
    printf("s=%d p=%d/n",s,p); 
} 

   本程序在main函数中和复合语句内两次定义了变量s,p为自动变量。按照C语言的规定,在复合语句内,应由复合语句中定义的s,p起做用,故s的值应为a+ a,p的值为a*a。退出复合语句后的s,p应为main所定义的s,p,其值在初始化时给定,均为100。从输出结果能够分析出两个s和两个p虽变量名相同, 但倒是两个不一样的变量。 
   4. 对构造类型的自动变量如数组等,不可做初始化赋值。 
   2、外部变量的类型说明符为extern 
   在前面介绍全局变量时已介绍过外部变量。这里再补充说明外部变量的几个特色: 
   1. 外部变量和全局变量是对同一类变量的两种不一样角度的提法。全局变量是从它的做用域提出的,外部变量从它的存储方式提出的,表示了它的生存期。 
   2. 当一个源程序由若干个源文件组成时, 在一个源文件中定义的外部变量在其它的源文件中也有效。例若有一个源程序由源文件F1.C和F2.C组成: 

    F1.C 

int a,b; /*外部变量定义*/ 
char c; /*外部变量定义*/ 
main() 
{ 
…… 
} 

   F2.C 

extern int a,b; /*外部变量说明*/ 
extern char c; /*外部变量说明*/ 
func (int x,y) 
{ 
…… 
} 

   在F1.C和F2.C两个文件中都要使用a,b,c三个变量。在F1.C文件中把a,b,c都定义为外部变量。在F2.C文件中用extern把三个变量说明为外部变量,表示这些变量已在其它文件中定义,并把这些变量的类型和变量名,编译系统再也不为它们分配内存空间。 对构造类型的外部变量, 如数组等能够在说明时做初始化赋值,若不赋初值,则系统自动定义它们的初值为0。 
       3、静态变量 
   静态变量的类型说明符是static。 静态变量固然是属于静态存储方式,可是属于静态存储方式的量不必定就是静态变量, 例如外部变量虽属于静态存储方式,但不必定是静态变量,必须由static加以定义后才能成为静态外部变量,或称静态全局变量。 对于自动变量,前面已经介绍它属于动态存储方式。 可是也能够用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式。 
由此看来, 一个变量可由static进行再说明,并改变其原有的存储方式。 
   1. 静态局部变量 
   在局部变量的说明前再加上static说明符就构成静态局部变量。 
   例如: 

static int a,b; 
static float array[5]={1,2,3,4,5}; 

 

   静态局部变量属于静态存储方式,它具备如下特色: 
   (1)静态局部变量在函数内定义,但不象自动变量那样,当调用时就存在,退出函数时就消失。静态局部变量始终存在着,也就是说它的生存期为整个源程序。 
   (2)静态局部变量的生存期虽然为整个源程序,可是其做用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。 
   (3)容许对构造类静态局部量赋初值。在数组一章中,介绍数组初始化时已做过说明。若未赋以初值,则由系统自动赋以0值。 
   (4)对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。 根据静态局部变量的特色, 能够看出它是一种生存期为整个源程序的量。虽然离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用, 并且保存了前次被调用后留下的值。 所以,当屡次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也能够达到上述目的,但全局变量有时会形成意外的反作用,所以仍以采用局部静态变量为宜。 
   [例5.15] 

main() 
{ 
    int i; 
    void f(); /*函数说明*/ 
    for(i=1;i<=5;i++) 
    f(); /*函数调用*/ 
} 
void f() /*函数定义*/ 
{ 
    auto int j=0; 
    ++j; 
    printf("%d/n",j); 
} 

   程序中定义了函数f,其中的变量j 说明为自动变量并赋予初始值为0。当main中屡次调用f时,j均赋初值为0,故每次输出值均为1。如今把j改成静态局部变量,程序以下: 

main() 
{ 
    int i; 
    void f(); 
    for (i=1;i<=5;i++) 
        f(); 
} 
void f() 
{ 
    static int j=0; 
    ++j; 
    printf("%d/n",j); 
} 
void f() 
{ 
    static int j=0; 
    ++j; 
    printf("%d/n",j); 
} 

   因为j为静态变量,能在每次调用后保留其值并在下一次调用时继续使用,因此输出值成为累加的结果。读者可自行分析其执行过程。 
   2.静态全局变量 
   全局变量(外部变量)的说明以前再冠以static 就构成了静态的全局变量。全局变量自己就是静态存储方式, 静态全局变量固然也是静态存储方式。 这二者在存储方式上并没有不一样。这二者的区别虽在于非静态全局变量的做用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其做用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。因为静态全局变量的做用域局限于一个源文件内,只能为该源文件内的函数公用, 所以能够避免在其它源文件中引发错误。从以上分析能够看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的做用域, 限制了它的使用范围。所以static 这个说明符在不一样的地方所起的做用是不一样的。应予以注意。 
   4、寄存器变量 
   上述各种变量都存放在存储器内, 所以当对一个变量频繁读写时,必需要反复访问内存储器,从而花费大量的存取时间。 为此,C语言提供了另外一种变量,即寄存器变量。这种变量存放在CPU的寄存器中,使用时,不须要访问内存,而直接从寄存器中读写, 这样可提升效率。寄存器变量的说明符是register。 对于循环次数较多的循环控制变量及循环体内反复使用的变量都可定义为寄存器变量。 
求1到200全部数之和。

main() 
{ 
    register i,s=0; 
    for(i=1;i<=200;i++) 
        s=s+i; 
    printf("s=%d/n",s); 
} 

   本程序循环200次,i和s都将频繁使用,所以可定义为寄存器变量。对寄存器变量还要说明如下几点:    1. 只有局部自动变量和形式参数才能够定义为寄存器变量。由于寄存器变量属于动态存储方式。凡须要采用静态存储方式的量不能定义为寄存器变量。    2. 在Turbo C,MS C等微机上使用的C语言中, 其实是把寄存器变量当成自动变量处理的。所以速度并不能提升。 而在程序中容许使用寄存器变量只是为了与标准C保持一致。3. 即便能真正使用寄存器变量的机器,因为CPU 中寄存器的个数是有限的,所以使用寄存器变量的个数也是有限的。 

相关文章
相关标签/搜索