The C Programming Language(第 2 版) 笔记 / 1 介绍 / 1.10 外部变量与作用域

目录、参考文献


1.10 外部变量与作用域

main 函数中的变量(如 line、longest 等)是 main 函数的私有变量或局部变量
由于它们是在 main 函数中声明的,因此其它函数不能直接访问它们
其它函数中声明的变量也同样如此
例如,getline 函数中声明的变量 i 与 copy 函数中声明的变量 i 没有关系
函数中的每个局部变量只在函数被调用时存在,在函数执行完毕退出时消失
这也是其它语言通常把这类变量称为自动变量的原因
以后我们使用 “ 自动变量 ” 代表 “ 局部变量 ”
第 4 章将讨论 static 存储类,这种类型的局部变量在多次函数调用之间保持值不变

由于自动变量只在函数调用执行期间存在
因此,在函数的两次调用之间,自动变量不保留前次调用时的赋值
且在每次进入函数时都要显式为其赋值
如果自动变量没有赋值, 则其中存放的是无效值

除自动变量外,还可以定义位于所有函数外部的变量
也就是说,在所有函数中都可以通过变量名访问这种类型的变量
这种机制类似于 Fortran 语言中的 COMMON 变量,或 Pascal 语言中最外层程序块声明的变量
由于外部变量可以在全局范围内访问,因此,函数间可以通过外部变量交换数据,而不必使用参数表
外部变量一直存在,而不是在函数调用时产生、在函数执行完毕时消失
即使在对外部变量赋值的函数返回后,这些变量仍将保持原来的值不变

外部变量必须定义在所有函数之外,且只能定义一次,定义后编译程序将为它分配存储单元
在每个需要访问外部变量的函数中,必须声明相应的外部变量,此时说明其类型
声明时可以用 extern 语句显式声明,也可以通过上下文隐式声明
为了更详细地讨论外部变量,我们改写上述打印最长文本行的程序,把 line、longest 与 max 声明成外部变量
这需要修改这 3 个函数的调用、声明与函数体

#include <stdio.h> 
#define MAXLINE 1000 /* maximum input line size */ 

int max; /* maximum length seen so far */ 
char line[MAXLINE]; /* current input line */ 
char longest[MAXLINE]; /* longest line saved here */

int getline(void); 
void copy(void);

/* print longest input line; specialized version */ 
main() 
{ 
    int len; 
    extern int max; 
    extern char longest[]; 
    max = 0; 
    while ((len = getline()) > 0) 
        if (len > max) { 
            max = len; 
            copy(); 
        } 
    if (max > 0) /* there was a line */ 
        printf("%s", longest); 
    return 0; 
}

/* getline: specialized version */ 
int getline(void) 
{ 
    int c, i; 
    extern char line[]; 
    for (i = 0; i < MAXLINE - 1 && (c = getchar()) != EOF && c != '\n'; ++i) 
        line[i] = c; 
    if (c == '\n') { 
        line[i] = c; 
        ++i; 
    }
    line[i] = '\0'; 
    return i; 
}

/* copy: specialized version */ 
void copy(void) 
{ 
    int i; 
    extern char line[], longest[]; 
    i = 0; 
    while ((longest[i] = line[i]) != '\0') 
        ++i; 
}

在该例子中,前几行定义了 main、getline 与 copy 函数使用的几个外部变量
声明了各外部变量的类型,这样编译程序将为它们分配存储单元
从语法角度看,外部变量的定义与局部变量的定义是相同的,但由于它们位于各函数的外部,因此这些变量是外部变量
函数在使用外部变量之前,必须要知道外部变量的名字
要达到该目的,一种方式是在函数中使用 extern 类型的声明
这种类型的声明除了在前面加了一个关键字 extern 外,其它方面与普通变量的声明相同

某些情况下可以省略 extern 声明
在源文件中,如果外部变量的定义出现在使用它的函数之前,那么在那个函数中就没有必要使用 extern 声明
因此,main、getline 及 copy 中的几个 extern 声明都是多余的
在通常的做法中,所有外部变量的定义都放在源文件的开始处,这样就可以省略 extern 声明

如果程序包含在多个源文件中,而某个变量在 file1 文件中定义、在 file2 和 file3 文件中使用
那么在文件 file2 与 file3 中就需要使用 extern 声明来建立该变量与其定义之间的联系
人们通常把变量和函数的 extern 声明放在一个单独的文件中(习惯上称之为头文件)
并在每个源文件的开头使用 #include 语句把所要用的头文件包含进来,后缀名 .h 约定为头文件名的扩展名
例如,标准库中的函数就是在类似于 <stdio.h> 的头文件中声明的
更详细的信息将在第 4 章中讨论,第 7 章及附录 B 将讨论函数库

在上述特别版本中,由于 getline 与 copy 函数都不带参数
因此从逻辑上讲,在源文件开始处它们的原型应该是 getline() 与 copy()
但为了与老版本的 C 语言程序兼容,ANSI C 语言把空参数表看成老版本 C 语言的声明方式,并且对参数表不再进行任何检查
在 ANSI C 中,如果要声明空参数表,则必须使用关键字 void 进行显式声明
第 4 章将对此进一步讨论

读者应该注意到,这节中我们在谈论外部变量时谨慎地使用了定义(define)与声明(declaration)这两个词
“ 定义 ” 表示创建变量或分配存储单元,而 “ 声明 ” 指的是说明变量的性质,但并不分配存储单元

顺便提一下,现在越来越多的人把用到的所有东西都作为外部变量使用
因为似乎这样可以简化数据的通信 —— 参数表变短了,且在需要时总可以访问这些变量
但是,即使在不使用外部变量的时候,它们也是存在的
过分依赖外部变量会导致一定的风险,因为它会使程序中的数据关系模糊不清
外部变量的值可能会被意外地或不经意地修改,而程序的修改又变得十分困难
我们前面编写的打印最长文本行的程序的第 2 个版本就不如第 1 个版本好,原因有两方面
其一便是使用了外部变量
另一方面,第 2 个版本中的函数将它们所操纵的变量名直接写入了函数,从而使这两个有用的函数失去了通用性

到目前为止,我们已经对 C 语言的传统核心部分进行了介绍
借助于这些少量的语言元素,我们已经能够编写出相当规模的有用的程序


目录、参考文献

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值