第二课

本课主题: 变量存储方式,内部与外部函数

教学目的: 掌握变量的作用域类型。掌握变量的存储类别。掌握不同作用域变量的存储方式。掌握多文件编译。工程项目的使用方法。掌握内部函数与外部函数的区别。外部函数的使用方法。

教学重点: 变量的作用域,变量的存储方式。

教学难点: 外部变量的说明与使用。工程项目的使用。外部函数概念及使用方法。

授课内容:

一、局部变量

  在一个函数内部定义的变量是内部变量,它只在本函数内有效,也就是说只有在本函数内才能引用它们,在此函数以外是不能使用这些变量的。

  主函数内定义的变量也是局部变量,其它函数不能引用。

例:

float f1(int a)
{
  int b,c;        
  c=b=a;   /*正确*/
  a+=3;      /*正确*/
}
char f2(int x,int y)
{
  int i,j;
  i=j=x+y;  /*正确*/
  b=i+j; */错误*/  
  m=89;  /*错误*/
}
main()
{
  int m,n;         /*主函数内定义的变量也是局部变量,其它函数不能引用*/
  m=0;  /*正确*/
  n=m+5;  /*正确*/
  x=5+y; /*错误*/
  b=8;  /*错误*/
}

二、全局变量

  在函数之外定义的变量称为外部变量,外部变量是全局变量。全局变量可以为本文件中其它函数所共用。即在全局变量定义点之后的所有函数都可以使用该变量。

int p=1,q=5;   /*外部变量*/

float f1(int a)
{
  int b,c;        
  c=b=a;   /*正确*/
  p+=3;      /*引用了全局变量p,调用该函数后,p值将变为3。正确*/
  c1='a';  /*错误,c1的定义点不在本函数之前。*/
}

char c1,c2;    /*外部变量,即全局变量*/
char f2(int x,int y)
{
  int i,j;
  i=j=x+y;  /*正确*/
  c1=c2='z';  /*正确*/
}
main()
{
  int m,n;         /*主函数内定义的变量也是局部变量,其它函数不能引用*/
 q=0;  /*正确*/
  c2='z';  /*正确*/
}

  全局变量增加了函数间联系的渠道。但不提倡用这种方式,因为它降低了函数的独立性。使得模块间的耦合增加,提高了程序的复杂性。

三、外部变量说明

  如果函数要使用外部变量,且这个外部变量的定义点在该函数之后,或定义点不在本文件内,则要进行外部变量的说明。例:

int max(int x,int y)
{
  return (x>y?x:y);
}
main()
{
  extern int a,b;    /*说明变量a,b是外部变量*/
  printf("%d",max(a,b));
}
int a=13,b=-8;         /*外部变量定义*/

  外部变量说明只是申明该变量是一个已在外部定义过的变量,可以在任何需要使用它的函数内作说明,但作说明的同时不能给该变量赋初值。

  注意:局部变量与外部变量同名时,在局部变量定义的函数内,外部变量不起作用,也不能在该函数内作此外部变量说明,否则会产生编译错误。

四、变量的存储类别

  把变量分为局部变量与外部变量是从变量的作用域来分的。

  如果从变量值存在的时间(即生存期)来分,可以分为静态存储变量和动态存储变量。

  内存中供用户使用的部分可分为:

程序区(放代码)
静态存储区(放数据)
动态存储区(放数据)

  变量的存储方式:

程序区(放代码)
静态存储区全局变量 局部静态变量(有static说明) int a; main() { static int b; }
动态存储区函数形参变量 局部自动变量(无static说明) 函数调用相关数据 int func1(int x) {} main() {int c; /省略了auto/ auto int d;/auto可以省/ }

五、局部变量的存储方式

  上面的表格中已经说明,局部变量的存储方式有两种:static 与auto ,如果不加以特别说明,系统默认为auto类型。

  两者的区别是什么呢?只要记住静态存储与动态存储的区别就可以了。

程序区(放代码)
静态存储区 存储的变量在整个程序运行期间有效,变量的值保持不变,直到有语句改变它。
动态存储区 当变量超出作用范围时,它的存储空间被收回,下次再分配到时,上次的值的状态不能保持。

  如果我们希望局部变量的值在离开作用域后仍能保持,则将它说明为静态局部变量。

  其它说明:

  1、局部静态变量赋初值只在编译时赋一次,程序运行时就不再执行赋初值的操作了。

  2、局部静态变量如果不赋初值则自动为0。自动变量不赋初值则初始值为随机数值。

int func(int a)
{ 
  static int m=4;
  auto int b=4,c;
  int d;
  m=m+a;
  b=b+a;
  c=c+a;
  d=d+a;
  printf("static m=%d auto b=%d  auto c=%d d=%d\n",m,b,c,d);
}  
main()
{
  func(1);
  func(1);
}
/*----------
results:
static m=5 auto b=5  auto c=349 d=26062
static m=6 auto b=5  auto c=350 d=26063
*/

六、全局变量的存储方式

  全局变量在函数的外部定义,编译时即在静态存储区分配空间。它可以为程序中的其它函数引用。

  如果其它文件中函数要引用它,则需在要引用它的文件中作extern说明。

  如果不想被其它文件中的函数引用,可以在定义时作static说明。

七、内部函数

  根据函数能否被其它源文件调用,将函数区分为内部函数和外部函数。

  如果一个函数只能被本文件中其它函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型前面加static。

  static 类型标识符 函数名(形参表)

  例:

/*e07-08.c*/

static int fun()
{
  printf("static fun.\n");
}
float fun2()                /*extern function too*/
{
  printf("no extern.\n");
}
extern int fun3()         /*remove keywords extern is ok*/
{
  printf("has extern.\n");
}

  上例中的fun函数因被定义为static类型,它不能被其它文件中的函数调用。

八、外部函数的说明

  上例中的fun2,fun3函数都是外部函数。对不加特别说明的,都认为是外部函数。

  TURBO C2.0中,主调函数调用其它文件中的外部函数可以不加外部函数说明。

九、外部函数的使用

注意:下面的示例包括三个文件。请按注释把下面的内容分开保存到指定名称的文件中。编译的方法请见下面的“多文件编译”一段。

/*e07-09.prj*/
e07-08.c
e07-09.c

/*e07-08.c*/
static int fun()
{
  printf("static fun.\n");
}
float fun2()                /*extern function too*/
{
  printf("no extern.\n");
}
extern int fun3()         /*remove keywords extern is ok*/
{
  printf("has extern.\n");
}

/*e07-09.c*/
/* no effect
extern in fun();
*/
main()
{
/* fun();  error */
 fun2();
 fun3();
}

十、多文件编译

  大型的软件开发往往由多人进行,且源程序代码量非常大,为便于合作和管理,通常把源代码放在多个文件中,编译时分别进行,最后把目标文件联接成可执行文件。

目标文件(.obj):

  这里要注意的是编译的过程中每一个源程序文件都要对应的生成一个目标文件,它的扩展名为obj。函数代码放在目标文件中,可以被其它的语言所调用,同样,C程序也可调用其它语言生成的目标文件中的函数。目标文件中存放数据、变量、和函数代码,只是它们在内存中的存储位置不确定。联接程序作的工作就是安排所有目标文件中的数据与函数代码,把存储位置确定下来,便于函数间的相互调用。

  多个文件的管理我们用工程项目文件来进行。工程项目文件的扩展名为prj,一个可执行文件对应一个工程项目文件。通常编译联接一个项目生成的可执行文件名称即项目文件名。

  下面是一个工程文件的内容:它分两行,每行是一个源程序文件名称。也就是说这个工程项目包括两个文件,分别是e07-08.c和e07-09.c。

chapter07-10.gif

  下面是e07-08.c文件的内容,注意此时要设置编译环境当前工程项目名称为e07-09.prj。(如何设置呢?打开project主菜单,光带停在第一行project name上时,打回车键,就会出现一个输入框,在框内输入项目文件名称后再打回车键即可。)

chapter07-11.gif

  设置好project name后,请大家看compile菜单:

chapter07-12.gif

  这时不管当前打开的文件是什么,都可联接当前项目了,生成的可执行文件名为e07-09.exe

  注意,项目文件中包括的源文件中只能有一个含有主函数main。

  下面是e07-09.c文件的内容。

chapter07-13.gif

  如何编译联接项目呢?在设置好上面的project name后(当然先要编辑好项目文件的内容啦),执行compile菜单中的make EXE file菜单项就行了。如果出现错误,请仔细加以更正后再试。

  看看工作的成果:

chapter07-14.gif

十一、我来试一试

  把学生管理的函数分类存放到不同的文件中,建立学生管理工程项目文件并联编。

十二、注意问题

  1、为什么要用多文件编译?

  2、项目文件的内容及作用?

  3、目标文件的作用?

十三、作业

标签: C程序设计, C语言, 函数

评论已关闭