C语言变量、函数的作用域及变量的存储方式

一.变量的作用域和存储方式

在C语言中每个变量都有两种基本属性:数据类型、数据的存储类别。

数据类型很多人都已熟知,例如:字符型(char)、整型(int)、浮点型(float)等等。存储类别是指数据在内存中的存储方式,C语言中的存储类别共有4种:自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)。根据变量的存储类别,可以知道变量的作用域和生存期。

1.自动变量。关键字为auto,但实际上“auto”通常都可以省略,函数中的局部变量如果不用关键字static来定义则都默认为自动类型(auto)的变量,在调用函数时系统会将这些变量分配到内存的动态存储区中,函数调用结束后这些存储空间将被释放。我们平常使用的函数中未用static定义的局部变量都是auto类型。

2.静态变量。关键字为static。静态变量包括全局变量和静态局部变量。全局变量在变量申请时自动存储到内存的静态存储区,即自动申请为静态变量。若希望函数中局部变量的值在函数调用结束后不消失,则需要用关键字static将该局部变量声明为静态局部变量,这些变量也被存储在内存的静态存储区。加上关键字static修饰后,原来的局部变量就类似于全局变量,它的值在下次调用该函数之前不会发生改变;与全局变量不同的是,全局变量的值可以在程序中的任何部分进行修改,而静态局部变量在程序中的其他部分是不可见的。为了说明关键字static的作用,举例如下:

#include<stdio.h>

void add()

{

  static int n=0;//申请静态变量n,对其赋初值操作仅仅在编译函数时进行一次

  printf("n = %d\n",n);

  n++;

}

int main(void)

{

  add();

  add();

  add();

}

运行结果:

n = 0

n = 1

n = 2

通过以上讨论,得出理解静态局部变量的几个要点:

(1)静态局部变量存储在内存的静态存储区。

(2)对静态局部变量赋初值是在编译时进行的,即仅赋值一次。如果定义静态局部变量时不赋初值,则编译器将自动对其赋初值0(对数值型变量)或空字符(对字符型变量)。

(3)静态局部变量的值在函数调用结束后不发生改变,但在程序中的其他部分是不可见的。

静态局部变量的缺点:

(1)需要多占用系统的内存。

(2)降低程序的可读性。当调用函数次数较多时,可能会分不清静态局部变量的当前值是什么。

因此,在非必要场合应减少使用静态局部变量。

3.寄存器变量。关键字register。变量的值一般是存储在计算机的内存中的,但对于一些频繁调用的变量,为了减少变量的调用时间可将其存在CPU的寄存器中,定义这样的变量需要使用关键字register。需要说明的是,现在优化的编译器能够识别使用频繁的变量,从而自动将其放入CPU的寄存器中,因此需要程序员使用register关键字来定义寄存器变量的场合较少。

4.外部变量。外部变量是在函数外部定义的全局变量。关键字“extern”主要用来扩展外部变量的作用域。通常来说,外部变量的生存周期为程序的整个运行过程,它的作用域从定义该变量处到本程序文件的末尾,在此范围内该变量都是可见的。但是如果需要扩展外部变量的作用范围,就需要用到关键字extern。有以下两种扩展外部变量的情况:

(1)在一个文件内扩展外部变量的作用域。外部变量的作用域从定义该变量处到本程序文件的末尾,如果需要在定义之前使用该外部变量,应在使用之前用extern对该变量进行外部变量声明。例如:

#include<stdio.h>

extern int a;//外部变量声明

 

void output()

{

  printf("a=%d\n",a);

}

 

int a =3;

 

int main(void)

{

  output();

  return 0;

}

如果程序中没有声明语句“extern int a;”则编译时会报错,因为变量output()函数中的变量a未定义就使用。

(2)将外部变量的作用域扩展到其他文件。如果在本文件中定义的变量希望能用于其他文件,则可以在需要用到该变量的文件开头加入外部变量声明。例如

//文件auto1.c

#include<stdio.h>

extern int a;

 

void output()

{

  printf("a=%d\n",a);

}

 

int main(void)

{

  output();

  return 0;

}

 

//文件auto2.c

int a = 1000;

文件auto1.c中的声明语句“extern int a;”是告诉编译器:int型变量已经在其他文件中定义。

关键字“static”可用来限定外部变量的使用范围。如果某些外部变量只希望在本文件中使用,禁止在该文件以外的地方引用,可以在定义时在该变量前加关键字static,在前面的例子中如果将文件auto2.c改为:

//文件auto2.c

static int a = 1000;

则编译时会出错,因为文件auto1.c中的a成了未定义的变量。

 

小结:static声明一个变量的作用是(1)局部变量用static声明,该变量将被存入静态存储区,该变量在程序执行期间不释放。(2)全局变量用static声明,该变量的作用域被限定在本文件,即用static声明的全局变量仅在当前文件可见。

 

二.函数的作用域

   C语言中的函数根据能否被其他源文件调用分为内部函数和外部函数。

   只能被本文件中其他函数调用的函数称为内部函数,内部函数也称为静态函数,用关键字static来声明。例如:

   static int fun(int a);

声明了一个内部函数fun(int a),该函数只能在本文件中可见。通常把只能由本文件使用的函数和外部变量放在本文件的开头用static声明,可以防止其他文件误调用,提高程序可靠性。这在多人合作编写的大型程序中非常有用。

   可供其他文件调用的函数称为外部函数,用关键字extern来声明。例如

   extern int fun(int a)

 {  

     …

 }

定义了一个外部函数。c语言中的函数默认为外部函数,因此函数定义时省略关键字extern则默认为外部函数。应注意的是:调用已经在其他文件中定义过的外部函数时,当前文件的开头需要加上被调用函数的extern声明,旨在告诉编译器:该函数已经在其他文件中定义过了。例如:

//文件extern1.c

#include <stdio.h>

extern int a ;

extern int sum(int x,int y);

 

int main(void)

{

  a = sum(2,3);

  printf("The sum is %d",a);

}

 

//文件extern2.c

int a = 8;

int sum(int x,int y)

{

  return (x+y);

}

文件extern1.c中“extern int sum(int x,int y);”语句声明sum()函数是已经在其他文件中定义过的函数,若没有该语句,编译器将报错:sum函数未定义就使用。

 

 

三.static、extern、auto的用法小结

   关键字static和关键字extern在声明函数和全局变量时有某种“互补性”。

   用关键字static声明定义的函数和全局变量作用域仅在当前文件,对其他文件不可见,不能被本文件以外的文件引用。函数和全局变量使用static声明,可以防止误操作。

   用关键字extern声明定义的函数和全局变量可以在本文件以外的使用,但使用时必须在使用文件的前面加上该函数或全局变量的extern声明。另外,默认的函数、全局变量均为extern类型,故定义其他文件可以使用的函数和全局变量时可省略extern声明。

   关键字static和关键字auto在声明定义局部变量时有某种“互补性”。

   用static声明定义的局部变量将被存入静态存储区,该变量在程序执行期间不释放,这种用法比较少见。

   用auto声明定义的局部变量将被存入动态存储区,每次函数调用结束后该内存空间就被释放,下次使用该变量时需要重新申请内存空间,重新赋初值,常见的局部变量均属这种类型,关键字auto可省略。

 

参考文献:《C语言程序设计》 第2版   谭浩强  清华大学出版社

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值