一、局部变量(本地变量)
局部变量: 函数体内声明的变量称为该函数的局部变量。
自动存储期 —— 局部变量存储空间必定存在的时间,也即变量的有效时间。声明后生效,函数返回后失效。
块作用域 —— 变量生效时的程序文本区域。即声明后到函数体末尾。
1、静态局部变量
变量声明时使用static
关键字,使之成为静态局部变量,具有静态存储期。变量声明后在整个程序执行期间都有效。
举例:
void f(void)
{
static int i; // static local variable
...
}
函数 f 返回后,变量 i 不会丢失其值,仍然有效。
2、形式参数
形式参数也具有自动存储期和快作用域,但函数每次调用之后都会被自动初始化,初始化为相应实际参数的值。
二、全局变量(外部变量)
全局变量: 声明在任何函数体外(包括main函数)的变量。
静态存储期 —— 同static声明的局部变量。程序执行期间始终保留。
文件作用域 —— 变量声明后到所在的文件末尾。跟随在外部变量声明之后的所有函数都可以访问(并修改)它。
全局变量的性质与宏定义的变量相似。
1、用全局变量实现栈
# include <stdbool.h>
#define STACK_SIZE 100
int contents[STACK_SIZE]; //全局变量
int top = 0; //全局变量
void make_empty(void)
{
top = 0;
}
bool is_empty(void)
{
return top == 0;
}
bool is_full(void)
{
return top == STAKE_SIZE;
}
void push(int i)
{
if( is_full ) stake_overflow();
else contents[top++] = i;
}
void pop(void)
{
if( is_empty ) stake_underflow();
else return contents[--top];
}
...
上述代码中,5个函数均访问了全局变量top,其中2个访问了全局变量contents。
2、全局变量的利弊
优点:
- 在多个函数必须共享同一变量,或少数几个函数必须共享大量变量时,十分方便。且便于修改。
缺点:
- 不利于程序维护,难以确定该变量对具体某个函数的影响;
- 变量赋值一旦出错,难以确定出错的函数;
- 使用了全局变量的函数可移植性差,难以在其他程序中复用。
为了提高可读性,全局变量命名时应有具体意义。
三、程序块
程序块,也称为块。复合语句是一种程序块,函数体也是程序块。
举例:
if(i>j){
int t = i;
i = j;
j = t;
}
对于以上程序,整个 if 语句是一个程序块,其中的每个子句也是程序块。
性质:
- 声明在程序块中的变量具有自动存储期:进入程序块分配内存单元,退出时收回。
- 变量具有块作用域,即不在块外引用。
四、作用域
最重要的作用域规则:
当程序块内声明一个标识符,且该标识符已经可见(具有文件作用域,或已经在某程序块内被声明过)。在该块内,新的声明取代旧的声明,当该块结束后,标识符重新获得原有含义。
举例:同一程序中 同名为 i 的不同变量
以上代码中,
- 声明1:i 是具有静态存储期和文件作用域的变量(全局变量);
- 声明2:i 是具有块作用域的形式参数;
- 声明3:i 是具有快作用域的自动变量;
- 声明3:i 是具有快作用域的自动变量。
五、构建C程序
单个文件的C程序结构:
- #include指令(预处理命令);
- #define指令(预处理命令,创建宏);
- 类型定义;
- 外部变量声明;
- 除main函数之外的函数原型;
- main函数的定义;
- 其他函数的定义。
建议:
每个函数定义前使用盒形注释,描述函数信息,包括函数名,函数目的,各形参的含义,返回值,罗列所有的副作用(例如修改了外部变量的值)